如何改造 Scrapy 從而實(shí)現(xiàn)多網(wǎng)站大規(guī)模爬???
Scrapy 框架默認(rèn)是用來(lái)開(kāi)發(fā)定向爬蟲(chóng)的。一般情況下,在 spiders 文件夾下面的一個(gè).py 文件對(duì)應(yīng)了一個(gè)網(wǎng)站的爬取。
但還有另外一種爬蟲(chóng),它不會(huì)拘泥于提取頁(yè)面上的特定文字,而是關(guān)注如何并行爬取非常多的網(wǎng)站。這種爬蟲(chóng)可以實(shí)現(xiàn)大規(guī)模的爬取。這種爬蟲(chóng),一般是從若干個(gè)種子網(wǎng)址開(kāi)始爬。進(jìn)入每個(gè)網(wǎng)址后,把該頁(yè)面的所有網(wǎng)址作為新的種子網(wǎng)址繼續(xù)爬取,源源不斷,生生不息。但爬到以后,一般直接把整個(gè)頁(yè)面的源代碼保存下來(lái),通過(guò) Kafka 或者其他組件傳給另外的服務(wù)進(jìn)行解析。
為了讓 Scrapy 適配這種通用的解析邏輯,需要做一些定制化修改。Scrapy 官方文檔中,給出了幾點(diǎn)修改建議。
修改調(diào)度隊(duì)列
Scrapy 默認(rèn)的調(diào)度隊(duì)列是scrapy.pqueues.ScrapyPriorityQueue,它適合做定向爬蟲(chóng)使用,對(duì)于通用爬蟲(chóng),我們應(yīng)該修改為scrapy.pqueues.DownloaderAwarePriorityQueue。在 settings.py文件中添加一行:
- SCHEDULER_PRIORITY_QUEUE = 'scrapy.pqueues.DownloaderAwarePriorityQueue'
提高并發(fā)量在
settings.py中增加配置:
- CONCURRENT_REQUESTS = 100
- CONCURRENT_REQUESTS_PER_DOMAIN = 100
但是并發(fā)量實(shí)際上受內(nèi)存和 CPU 的限制,建議實(shí)際測(cè)試,選擇最適合的數(shù)字。
提高 Twisted IO 線程池大小
Scrapy 在做 DNS 解析的時(shí)候,是阻塞式的。所以請(qǐng)求量越高,解析 DNS 就會(huì)越慢。為了避免這個(gè)情況,可以提高線程池的大小。在 settings.py中增加一個(gè)配置:
- REACTOR_THREADPOOL_MAXSIZE = 20
搭建專用 DNS 服務(wù)器
如果爬蟲(chóng)進(jìn)程數(shù)太多,并發(fā)又太快,可能會(huì)對(duì) DNS 服務(wù)器形成 Dos 攻擊。所以建議自己?jiǎn)为?dú)搭建一個(gè) DNS 服務(wù)器。
減少日志量
Scrapy 默認(rèn)是 DEBUG 級(jí)別的日志等級(jí),每次爬取會(huì)產(chǎn)生大量的日志。通過(guò)把日志等級(jí)調(diào)整到INFO 可以大大減少日志量。在 settings.py 中增加一行:
- LOG_LEVEL = 'INFO'
禁用 Cookies 和自動(dòng)重試
大規(guī)模爬蟲(chóng)一般不需要用到 Cookies,所以可以把它禁用。請(qǐng)求失敗的自動(dòng)重試會(huì)降低爬蟲(chóng)的速度。但是由于大規(guī)模爬蟲(chóng)的爬取范圍很大,對(duì)于個(gè)別失敗的請(qǐng)求沒(méi)有必要重試。因此修改settings.py:
- COOKIES_ENABLED = False
- RETRY_ENABLED = False
降低請(qǐng)求超時(shí)時(shí)間,禁用自動(dòng)跳轉(zhuǎn)
有些網(wǎng)址因?yàn)檫h(yuǎn)在大洋彼岸或者受到了干擾,請(qǐng)求響應(yīng)時(shí)間很長(zhǎng)。對(duì)于這種網(wǎng)址,應(yīng)該果斷放棄,避免影響其他網(wǎng)址的爬取。
禁用自動(dòng)跳轉(zhuǎn)功能,也有助于提高網(wǎng)頁(yè)訪問(wèn)速度。
- DOWNLOAD_TIMEOUT = 10
- REDIRECT_ENABLED = False
使用廣度有限搜索
Scrapy 默認(rèn)基于深度優(yōu)先(DFO)搜索算法。但在大規(guī)模爬蟲(chóng)中,我們一般會(huì)使用廣度有限(BFO)搜索算法:
- DEPTH_PRIORITY = 1
- SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'
- SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'
關(guān)注內(nèi)存,謹(jǐn)防內(nèi)存泄露如果你發(fā)現(xiàn)爬蟲(chóng)占用大量?jī)?nèi)存,但是速度遠(yuǎn)遠(yuǎn)低于你設(shè)置的并發(fā)速度,那么要考慮是否發(fā)生了內(nèi)存泄露。