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

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

簡(jiǎn)單爬蟲架構(gòu)

框架

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

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

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

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

爬蟲調(diào)度端

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

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

        urlManager.addUrls(urls)  #將新的url加入U(xiǎn)RL管理器

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


右下角Request Headers

完整代碼:

import requests
from urlManager import UrlManager #url管理器
from htmlDownloader import HtmlDownloader #頁(yè)面下載器
from htmlParser import HtmlParser #網(wǎng)頁(yè)解析器
#請(qǐ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('爬蟲開(kāi)始...')
    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)
        #文件處理儲(chǔ)存
            urlManager.addUrls(urls)

URL管理器

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

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

完整代碼:

class UrlManager(object):

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

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

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

    def getUrl(self): #該函數(shù)返回url視為已訪問(wèn)
        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)頁(yè)下載器

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

完整代碼:

import requests

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

網(wǎng)頁(yè)解析器

網(wǎng)頁(yè)解析器使用了BeautifulSoup模塊厉膀,非常方便快捷
具體參考BeautifulSoup文檔
像我就記不太住溶耘,都是隨用隨查的,所以這是最費(fèi)時(shí)間的一部分服鹅,也很容易出錯(cuò)(逃
這里需要我們自己分析頁(yè)面來(lá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)

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

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

爬蟲結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末聚蝶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子藻治,更是在濱河造成了極大的恐慌碘勉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桩卵,死亡現(xiàn)場(chǎng)離奇詭異验靡,居然都是意外死亡倍宾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門胜嗓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)高职,“玉大人,你說(shuō)我怎么就攤上這事辞州≌浚” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵变过,是天一觀的道長(zhǎng)埃元。 經(jīng)常有香客問(wèn)我,道長(zhǎng)媚狰,這世上最難降的妖魔是什么岛杀? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮崭孤,結(jié)果婚禮上类嗤,老公的妹妹穿的比我還像新娘。我一直安慰自己辨宠,他們只是感情好遗锣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著嗤形,像睡著了一般精偿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上派殷,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音墓阀,去河邊找鬼毡惜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斯撮,可吹牛的內(nèi)容都是我干的经伙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼勿锅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帕膜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起溢十,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤垮刹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后张弛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體荒典,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酪劫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寺董。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片覆糟。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖遮咖,靈堂內(nèi)的尸體忽然破棺而出滩字,到底是詐尸還是另有隱情,我是刑警寧澤御吞,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布麦箍,位于F島的核電站,受9級(jí)特大地震影響魄藕,放射性物質(zhì)發(fā)生泄漏内列。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一背率、第九天 我趴在偏房一處隱蔽的房頂上張望话瞧。 院中可真熱鬧,春花似錦寝姿、人聲如沸交排。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)埃篓。三九已至,卻和暖如春根资,著一層夾襖步出監(jiān)牢的瞬間架专,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工玄帕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留部脚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓裤纹,卻偏偏與公主長(zhǎng)得像委刘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鹰椒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 爬蟲文章 in 簡(jiǎn)書程序員專題: like:128-Python 爬取落網(wǎng)音樂(lè) like:127-【圖文詳解】py...
    喜歡吃栗子閱讀 21,737評(píng)論 4 412
  • Python開(kāi)發(fā)簡(jiǎn)單爬蟲(Python2.X版本锡移,Eclipse工具) 一、爬蟲介紹 爬蟲調(diào)度端:?jiǎn)?dòng)漆际、停止爬蟲淆珊,...
    凜0_0閱讀 2,129評(píng)論 2 10
  • 1 前言 作為一名合格的數(shù)據(jù)分析師,其完整的技術(shù)知識(shí)體系必須貫穿數(shù)據(jù)獲取奸汇、數(shù)據(jù)存儲(chǔ)套蒂、數(shù)據(jù)提取钞支、數(shù)據(jù)分析、數(shù)據(jù)挖掘操刀、...
    whenif閱讀 18,052評(píng)論 45 523
  • 14天訓(xùn)練營(yíng)結(jié)束了烁挟,感覺(jué)有點(diǎn)兒不自在。 訓(xùn)練營(yíng)期間骨坑,睜開(kāi)眼的第一件事就是看看今天的晨讀推送了沒(méi)有撼嗓,如果看到有推送,...
    小沙彌_383c閱讀 200評(píng)論 0 1
  • 不久欢唾,村里就接到了上面發(fā)下來(lái)的通知且警,說(shuō)紅旗村的土地將被國(guó)家占用,修建一個(gè)新縣城礁遣,而村里人不僅將得到安置費(fèi)斑芜,...
    宮長(zhǎng)青箏閱讀 113評(píng)論 0 0