簡單爬蟲架構(gòu)的實(shí)現(xiàn)

在我的上一篇文章里簡單介紹了一下最簡單的爬蟲架構(gòu):《淺談簡單爬蟲架構(gòu)》
如下圖所示

簡單爬蟲架構(gòu)

框架

mySpider
├─ spiderMain.py #爬蟲調(diào)度端
├─ urlManager.py #URL管理器
├─ htmlDownloader.py #網(wǎng)頁下載器
└─ htmlParser.py #網(wǎng)頁解析器

此篇以爬取廖雪峰的官方網(wǎng)站中的python教程為例

不過廖老師的網(wǎng)站對爬蟲進(jìn)行了過濾,建議舉一反三,嘗試爬取其他網(wǎng)站

現(xiàn)在的網(wǎng)絡(luò)爬蟲越來越多,有很多爬蟲都是初學(xué)者寫的,和搜索引擎的爬蟲不一樣,他們不懂如何控制速度,結(jié)果往往大量消耗服務(wù)器資源,導(dǎo)致帶寬白白浪費(fèi)了。
其實(shí)Nginx可以非常容易地根據(jù)User-Agent過濾請求,我們只需要在需要URL入口位置通過一個簡單的正則表達(dá)式就可以過濾不符合要求的爬蟲請求:
...
location / {
if ($http_user_agent ~* "python|curl|java|wget|httpclient|okhttp") {
return 503;
}
# 正常處理
...
}
...
變量$http_user_agent是一個可以直接在location中引用的Nginx變量。~*表示不區(qū)分大小寫的正則匹配,通過python就可以過濾掉80%的Python爬蟲

爬蟲調(diào)度端

爬蟲調(diào)度端的核心代碼實(shí)現(xiàn):

while urlManager.hasUrl(): #詢問url管理器是否有待爬url
        newurl = urlManager.getUrl() #獲取待爬url
        html = htmlDownloader.download(newurl,headers) #下載頁面
        (title,content),urls = htmlParser.parser(html) #從頁面中解析出內(nèi)容和新的url
  
        #此處可以處理爬下來的文件,比如儲存到本地,我僅打印標(biāo)題以測試
        print(title)

        urlManager.addUrls(urls)  #將新的url加入URL管理器

其中的headers是請求頭,用于模擬瀏覽器的行為
可以使用chrome瀏覽器的開發(fā)者工具找到
網(wǎng)頁右擊 檢查->network
刷新頁面


右下角Request Headers

完整代碼:

import requests
from urlManager import UrlManager #url管理器
from htmlDownloader import HtmlDownloader #頁面下載器
from htmlParser import HtmlParser #網(wǎng)頁解析器
#請求頭
headers={'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8','Accept-Encoding':'gzip, deflate, br','Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8','Cache-Control':'max-age=0','Connection':'keep-alive','Cookie':'Hm_lvt_2efddd14a5f2b304677462d06fb4f964=1516595211; atsp=1516853801496_1516853801154; Hm_lpvt_2efddd14a5f2b304677462d06fb4f964=1516853818','Host':'www.liaoxuefeng.com','Referer':'https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318447437605e90206e261744c08630a836851f5183000','Upgrade-Insecure-Requests':'1','User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

if __name__ == '__main__':
    print('爬蟲開始...')
    urlManager = UrlManager()
    htmlDownloader = HtmlDownloader()
    htmlParser = HtmlParser()
    urlManager.addUrl('https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000')
    while urlManager.hasUrl():
        newurl = urlManager.getUrl()
        if newurl != "":
            html = htmlDownloader.download(newurl,headers)
            (title,content),urls = htmlParser.parser(html)
            print(title)
        #文件處理儲存
            urlManager.addUrls(urls)

URL管理器

url管理器可以使用queue或set甚至list來實(shí)現(xiàn),如果需要按順序爬取,可以使用隊(duì)列來實(shí)現(xiàn),即先加入url管理器的url先爬取,但是需要注意的是使用隊(duì)列則需要檢查待加入的url是否已經(jīng)在隊(duì)列中了。
而如果對順序沒有特別的要求,使用set更為簡便,可以直接加入待爬url,因?yàn)橹貜?fù)的元素只會在set中出現(xiàn)一次。

但無論使用queue、set還是list實(shí)現(xiàn),都需要檢查待加的url是否已經(jīng)爬過了,以此避免重復(fù)爬取甚至循環(huán)爬取

完整代碼:

class UrlManager(object):

    def __init__(self):
        self._newUrls = set([]) #set newUrls中儲存未訪問的url 
        self._oldUrls = set([]) #set oldUrls中儲存已訪問的url

    def addUrl(self,url): #添加url
        if isinstance(url,str) and url not in self._oldUrls: 
            self._newUrls.add(url)

    def hasUrl(self): #是否還有未訪問的url
        return len(self._newUrls) > 0 

    def getUrl(self): #該函數(shù)返回url視為已訪問
        if  not self._newUrls: #不存在新的url
            return ""
        url = self._newUrls.pop()
        self._oldUrls.add(url)
        return url

    def addUrls(self,urls):
        if isinstance(urls,list):
            for url in urls:
                if url not in self._oldUrls:
                    self._newUrls.add(url)

網(wǎng)頁下載器

網(wǎng)頁下載器十分簡單,在此使用了request模塊
詳情可以查看request模塊文檔

完整代碼:

import requests

class HtmlDownloader(object):
    
    def download(self,url,headers=""): #url:待爬鏈接 headers:請求頭  return value:html文本
        if url is None or not isinstance(url,str):
            #獲取失敗錯誤處理
            return None
        r = requests.get(url,headers=headers)
        return r.text

網(wǎng)頁解析器

網(wǎng)頁解析器使用了BeautifulSoup模塊,非常方便快捷
具體參考BeautifulSoup文檔
像我就記不太住,都是隨用隨查的,所以這是最費(fèi)時間的一部分,也很容易出錯(逃
這里需要我們自己分析頁面來解析

完整代碼:

from bs4 import BeautifulSoup

baseUrl = 'https://www.liaoxuefeng.com'

class HtmlParser(object):
    def parser(self,text): #text: html文本  return value: (需要的數(shù)據(jù),list[需要的url])
        soup = BeautifulSoup(text,'lxml')
        #獲取標(biāo)題
        title = soup.h4
        #print(soup.select(".x-main-content"))
        if len(soup.select(".x-main-content")) >0:
        #   print("True")
            content = soup.select(".x-main-content")[0].get_text()
        else:
        #   print("False")
            content=""
        urls = []
        for a in soup.find_all('a',"x-wiki-index-item"):
            urls.append(baseUrl+a.get('href'))  
        return ((title,content),urls)

價值數(shù)據(jù)

做到這里,我們就已經(jīng)可以獲取到我們想要的價值數(shù)據(jù)了。
在這里我僅打印標(biāo)題以測試,實(shí)際上我們可以對數(shù)據(jù)做更多的處理,而這就需要我們繼續(xù)深入學(xué)習(xí)了。共勉!

爬蟲結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 爬蟲文章 in 簡書程序員專題: like:128-Python 爬取落網(wǎng)音樂 like:127-【圖文詳解】py...
    喜歡吃栗子閱讀 22,749評論 4 411
  • Python開發(fā)簡單爬蟲(Python2.X版本,Eclipse工具) 一、爬蟲介紹 爬蟲調(diào)度端:啟動、停止爬蟲,...
    凜0_0閱讀 2,204評論 2 10
  • 1 前言 作為一名合格的數(shù)據(jù)分析師,其完整的技術(shù)知識體系必須貫穿數(shù)據(jù)獲取、數(shù)據(jù)存儲、數(shù)據(jù)提取、數(shù)據(jù)分析、數(shù)據(jù)挖掘、...
    whenif閱讀 18,319評論 45 523
  • 14天訓(xùn)練營結(jié)束了,感覺有點(diǎn)兒不自在。 訓(xùn)練營期間,睜開眼的第一件事就是看看今天的晨讀推送了沒有,如果看到有推送,...
    小沙彌_383c閱讀 288評論 0 1
  • 不久,村里就接到了上面發(fā)下來的通知,說紅旗村的土地將被國家占用,修建一個新縣城,而村里人不僅將得到安置費(fèi),...
    宮長青箏閱讀 151評論 0 0

友情鏈接更多精彩內(nèi)容