哈嘍,大家好, 我要開始寫部落格啦💪..... 文中有不當之處, 還請多多指正~謝謝
1.前言
在網上找書籍或其他資源的時候,都會看到某些資源網站上寫著“資訊來源網際網路”。於是乎,我也開始“搭弓射箭”,找來了python老弟,幫我研究研究到底如何才能爬爬爬~。
首先, 第一版我用了requests工具, 好像是python 老弟自帶的 ... 用它不是不行, 就是不行, 用各種代理, 還是拉垮... 那就over
後來又研究了selenium, 這玩意配置起來賊費勁, 必須各種瀏覽器驅動版本對應,最後也是over
最後最後發現還挺不拉垮的DrissionPage, 也不知道那個大牛天天沒事幹,搞出個這麼好用的玩意 ...
廢話不多說, 咱們直接開幹
先看一下最後的結果截圖
2.邏輯思路
其實邏輯非常簡單:
- 開啟網頁
- 輸入百度地址
- 查詢關鍵字
- 獲取查詢到的頁面地址(頁碼數自己設定)
- 從獲取到的頁面中找我想要的資源 (這裡是網盤資源)
- 把結果寫入到excel
- over。over
3.函式定義
先介紹一下我都“裝載”了哪些函式:
#儲存結果佇列
data=queue.Queue()
#用它來開啟瀏覽器,百度輸入關鍵字,查詢並返回結果(查詢到的url,百度一頁有10個結果)
#key 百度查詢關鍵字
#port 埠號 這裡是個坑,因為不自定義埠號, 它就會重複使用某個埠號,多執行緒時經常錯誤, 找不到元素,因為你懂的...
def baiduGetUrl(key,port):
#return ['http://....',*,*]
pass
#獲取html內容,中間會有一些關閉按鈕的使用 (開啟網頁, 它給你個彈窗,你說你關不關它)
#url 地址是baidu給的...
#port 埠(隨機自定義 要大一些 你懂的)
def getHtml(url,port):
#return page.html
pass
#找到匹配的內容
def searchHtml(html,url):
#soup.find_all(....)
#return result
pass
#負責“獲取html”和”找到html匹配的內容“
def getHtmlProc(url,port):
pass
#負責寫入檔案
def create_excel(filename):
pass
#主程式會開啟多程序,呼叫這個函式
#key 百度查詢關鍵字 port埠
def eachGetData(key,port):
#獲取輸入的key 查詢到的地址,也就是call baiduGetUrl
#遍歷地址,開啟幾個執行緒,執行getHtmlProc
#最後將結果寫入檔案 create_excel
4.核心程式碼演示
不知道小夥伴們有沒有看懂函式定義部分, 也不知道我那麼定義有沒有毛病, 管他呢, 能執行就不錯了...
下面簡單程式碼演示一下, 文末會給出整個程式碼的連結哦~
檢視程式碼 def baiduGetUrl(key,port):
resultUrl=[]
co = ChromiumOptions().headless()
co.auto_port()
co.set_local_port(9432+port)
page = ChromiumPage(co)
page.get("http://www.baidu.com", retry=999)
page.wait.load_start()
page('#kw').input(key)
page("#su").click()
page.wait.load_start()
for i in range(1,16):
try:
next_page = page.ele("@text()=下一頁 >") # 百度的下一頁
if i!=1:
if not next_page:
next_page=page.ele("@text()=下一頁 >")
print(next_page)
next_page.click()
page.wait.load_start()
time.sleep(2)
divs=page.eles("t:h3")
for d in divs:
a=d.ele("t:a")
resultUrl.append(a.attrs.get("href"))
except Exception as ex:
logger.error("下一頁時錯誤:"+str(ex))
print("下一頁時錯誤:"+str(ex))
pass
page.close()
print("獲取到的頁面url=%d"%len(resultUrl))
return resultUrl
檢視程式碼
def getHtml(url,port):
try:
co = ChromiumOptions().headless()#
co.auto_port()
thread_id=threading.currentThread().ident
r=random.Random()
num=r.randint(1,40000)
thisprot=9012+port+int(str(thread_id)[0:3])+num
print("埠號: %d " %(thisprot,))
co.set_local_port(thisprot)
page = ChromiumPage(co)
page.get(url, retry=999)
page.wait.load_start()
time.sleep(1)
try:
btn = page.ele("@aria-label:關閉")
# 某些網站的關閉按鈕
if btn:
btn.click()
except:
pass
try:
btnimg = page.ele("@style^position: absolute;top: 16px;left: -20px;width: 16px;height: 16px")
# csdn 關閉
if btnimg:
btnimg.click()
except:
pass
try:
btnbdba = page.ele("@class=close-btn")
if btnbdba:
btnbdba.click()
except:
pass
try:
btnin=page.ele("@id=access")
if btnin:
btnin.click()
except:
pass
try:
btnClose= page.ele("@class=close")
if btnClose:
btnClose.click()
except:
pass
html=page.html
page.close()
print("獲取到html 內容")
return html
except Exception as ex:
logger.error("獲取html遇到錯誤:"+str(ex))
print("獲取html遇到錯誤:"+str(ex))
return ""
這裡的找結果的方法多少有點簡陋, 會找到一些錯誤的結果, 也有一些結果已經過期(資源連結過期), 這有待完善哦。。
檢視程式碼 def searchHtml(html,url):
findData = []
soup = BeautifulSoup(html, 'html.parser')
print("獲取到html")
textFindEle = soup.find_all(
string=lambda text: text and (text.startswith('連結') or text.startswith(' 連結') or text.startswith(
'百度網盤地址') or text.startswith('地址') or text.startswith('網盤地址')))
hrefFindEle = soup.find_all('a', href=lambda href: href
and (href.startswith('https://pan.baidu.com/s')
or href.startswith('https://pan.baidu.com/share/init?')
or href.startswith('https://pan.quark.cn/s/')
or href.startswith('https://url98.ctfile.com/d')))
print("找到結果 text=%d ,href=%d " % (len(textFindEle), len(hrefFindEle),))
if len(textFindEle)!=0:
for textf in textFindEle:
prev = textf.previous_sibling
next = textf.next_sibling
try:
findData.append(
{"prev": prev and prev.text, 'next': next and next.text, "thist": textf and textf.text, "url": url,
"thish": textf.attrs.get('href')})
except:
findData.append(
{"prev": prev and prev.text, 'next': next and next.text, "thist": textf and textf.text, "url": url,
"thish": ''})
pass
if len(hrefFindEle)!=0:
for href in hrefFindEle:
prev = href.previous_sibling
next = href.next_sibling
try:
findData.append(
{"prev": prev and prev.text, 'next': next and next.text, "thist": href and href.text, "url": url,
"thish": href.attrs.get('href')})
except:
findData.append(
{"prev": prev and prev.text, 'next': next and next.text, "thist": href and href.text, "url": url,
"thish": ''})
pass
if len(findData)!=0:
print("結果新增到佇列")
data.put(findData)
5.這裡就要結束了
總體來看,程式碼還是可以找到一些想要的結果的。
整體優缺點的話, 個人覺得程式碼改成多程序(multiprocessing.Process,百度說是開啟子程序,不知道他有沒有騙我)然後在子程序中開啟了多個執行緒(限制3,4個同時執行)。。。 不能搞太多, 太多電腦大哥就不幹了,第三方外掛庫也不幹。。
比單執行緒要快很多, 但是, 也需要挺長時間查詢結果的。。
還有就是結果的正確性問題, 如何更精準的找到結果? ok , 此事仍待大神...
最後
感謝閱讀, 程式碼關注公眾號回覆“python小爬蟲”即可收到連結哦。 有問題隨時留言評論, 對了,點個贊再走唄