爬虫总结(四)-- 分布式爬虫
分布式爬蟲的演習(xí)。
分布式爬蟲問(wèn)題其實(shí)也就是多臺(tái)機(jī)器多個(gè) spider 對(duì) 多個(gè) url 的同時(shí)處理問(wèn)題,怎樣 schedule 這些 url,怎樣匯總 spider 抓取的數(shù)據(jù)。最簡(jiǎn)單粗暴的方法就是將 url 進(jìn)行分片,交給不同機(jī)器,最后對(duì)不同機(jī)器抓取的數(shù)據(jù)進(jìn)行匯總。然而這樣每個(gè) spider 只能對(duì)自己處理的 url 去重,沒(méi)辦法全局的去重,另外性能也很難控制,可能有某臺(tái)機(jī)器很早就跑完了,而別的機(jī)器還要跑很久。另一種思路就是把 url 存在某個(gè)地方,共享給所有的機(jī)器,總的調(diào)度器來(lái)分配請(qǐng)求,判斷 spider 有沒(méi)有閑置,閑置了就繼續(xù)給它任務(wù),直到所有的 url 都爬完,這種方法解決了去重問(wèn)題(下面會(huì)具體講到),也能提高性能,scrapy-redis 就實(shí)現(xiàn)了這樣一個(gè)完整框架,總的來(lái)說(shuō),這更適合廣度優(yōu)先的爬取。
Scrapyd
Scrapy 并沒(méi)有提供內(nèi)置的分布式抓取功能,不過(guò)有很多方法可以幫你實(shí)現(xiàn)。
如果你有很多個(gè)spider,最簡(jiǎn)單的方式就是啟動(dòng)多個(gè) Scrapyd 實(shí)例,然后將spider分布到各個(gè)機(jī)器上面。
如果你想多個(gè)機(jī)器運(yùn)行同一個(gè)spider,可以將url分片后交給每個(gè)機(jī)器上面的spider。比如你把URL分成3份
http://somedomain.com/urls-to-crawl/spider1/part1.list http://somedomain.com/urls-to-crawl/spider1/part2.list http://somedomain.com/urls-to-crawl/spider1/part3.list然后運(yùn)行3個(gè) Scrapyd 實(shí)例,分別啟動(dòng)它們,并傳遞part參數(shù)
curl http://scrapy1.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=1 curl http://scrapy2.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=2 curl http://scrapy3.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1Crawlera
這個(gè),花錢就可以輕易解決~?直達(dá)
Scrapy-redis
Redis 是高性能的 key-value 數(shù)據(jù)庫(kù)。我們知道 MongoDB 將數(shù)據(jù)保存在了硬盤里,而 Redis 的神奇之處在于它將數(shù)據(jù)保存在了內(nèi)存中,因此帶來(lái)了更高的性能。
分布式原理
scrapy-redis實(shí)現(xiàn)分布式,其實(shí)從原理上來(lái)說(shuō)很簡(jiǎn)單,這里為描述方便,我們把自己的核心服務(wù)器稱為 master,而把用于跑爬蟲程序的機(jī)器稱為 slave。
回顧?scrapy 框架,我們首先給定一些start_urls,spider 最先訪問(wèn) start_urls 里面的 url,再根據(jù)我們的 parse 函數(shù),對(duì)里面的元素、或者是其他的二級(jí)、三級(jí)頁(yè)面進(jìn)行抓取。而要實(shí)現(xiàn)分布式,只需要在這個(gè)starts_urls里面做文章就行了。進(jìn)一步描述如下:
master 產(chǎn)生 starts_urls,url 會(huì)被封裝成 request 放到 redis 中的 spider:requests,總的 scheduler 會(huì)從這里分配 request,當(dāng)這里的 request 分配完后,會(huì)繼續(xù)分配 start_urls 里的 url。
slave 從 master 的 redis 中取出待抓取的 request,下載完網(wǎng)頁(yè)之后就把網(wǎng)頁(yè)的內(nèi)容發(fā)送回 master 的 redis,key 是 spider:items。scrapy 可以通過(guò) settings 來(lái)讓 spider 爬取結(jié)束之后不自動(dòng)關(guān)閉,而是不斷的去詢問(wèn)隊(duì)列里有沒(méi)有新的 url,如果有新的 url,那么繼續(xù)獲取 url 并進(jìn)行爬取,所以這一過(guò)程將不斷循環(huán)。
master 里的 reids 還有一個(gè) key 是 “spider:dupefilter” 用來(lái)存儲(chǔ)抓取過(guò)的 url 的 fingerprint(使用哈希函數(shù)將url運(yùn)算后的結(jié)果),防止重復(fù)抓取,只要 redis 不清空,就可以進(jìn)行斷點(diǎn)續(xù)爬。
對(duì)于已有的 scrapy 程序,對(duì)其擴(kuò)展成分布式程序還是比較容易的。總的來(lái)說(shuō)就是以下幾步:
關(guān)于 scheduler 到底是怎么進(jìn)行調(diào)度的,需要看源碼進(jìn)行分析。
源碼分析
可能上面的描述還是不夠清楚,干脆看一下源碼吧,scrapy-redis 主要要一下幾個(gè)文件。
零件分析
connection.py
根據(jù) settings 里的配置實(shí)例化 redis 連接,被 dupefilter 和 scheduler 調(diào)用。
dupefilter.py
對(duì) request 進(jìn)行去重,使用了 redis 的 set。
queue.py
三種 queue, SpiderQueue(FIFO), SpiderPriorityQueue,以及 SpiderStack(LIFI)。默認(rèn)使用的是第二種。
pipelines.py
分布式處理,將 item 存儲(chǔ)在 redis 中。
scheduler.py
取代 scrapy 自帶的 scheduler,實(shí)現(xiàn)分布式調(diào)度,數(shù)據(jù)結(jié)構(gòu)來(lái)自 queue。
spider.py
定義 RedisSpider.py, 繼承了 RedisMixin 和 CrawlSpider。
由上可知,scrapy-redis 實(shí)現(xiàn)的?爬蟲分布式?和?item處理分布式?就是由模塊 scheduler 和模塊 pipelines 實(shí)現(xiàn)。上述其它模塊作為為二者輔助的功能模塊。
調(diào)度過(guò)程
初始化
spider 被初始化時(shí),同時(shí)會(huì)初始化一個(gè)對(duì)應(yīng)的 scheduler 對(duì)象,這個(gè)調(diào)度器對(duì)象通過(guò)讀取 settings,配置好自己的調(diào)度容器 queue 和判重工具dupefilter。
判重 & 進(jìn)入調(diào)度池
每當(dāng)一個(gè) spider 產(chǎn)出一個(gè) request 的時(shí)候,scrapy 內(nèi)核會(huì)把這個(gè) request 遞交給這個(gè) spider 對(duì)應(yīng)的 scheduler 對(duì)象進(jìn)行調(diào)度,scheduler 對(duì)象通過(guò)訪問(wèn) redis 對(duì) request 進(jìn)行判重,如果不重復(fù)就把他添加進(jìn) redis 中的調(diào)度池。
調(diào)度
當(dāng)調(diào)度條件滿足時(shí),scheduler 對(duì)象就從 redis 的調(diào)度池中取出一個(gè) request 發(fā)送給spider,讓 spider 爬取,若爬取過(guò)程中返回更多的url,那么繼續(xù)進(jìn)行直至所有的 request 完成。在這個(gè)過(guò)程中通過(guò) connect signals.spider_idle 信號(hào)對(duì) crawler 狀態(tài)的監(jiān)視,scheduler 對(duì)象發(fā)現(xiàn) 這個(gè) spider 爬取了所有暫時(shí)可用 url,對(duì)應(yīng)的 redis 的調(diào)度池空了,于是觸發(fā)信號(hào) spider_idle,spider收到這個(gè)信號(hào)之后,直接連接 redis 讀取 strart_url池,拿去新的一批 url,返回新的 make_requests_from_url(url) 給引擎,進(jìn)而交給調(diào)度器調(diào)度。
熟悉了原理其實(shí)可以自己來(lái)寫 scheduler,自己定義調(diào)度優(yōu)先級(jí)和順序,
總結(jié)
以上是生活随笔為你收集整理的爬虫总结(四)-- 分布式爬虫的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 爬虫总结(三)-- cloud scra
- 下一篇: 爬虫总结(五)-- 其他技巧