1. 程式人生 > >scrapy-redis所有request爬取完畢,如何解決爬蟲空跑問題?

scrapy-redis所有request爬取完畢,如何解決爬蟲空跑問題?

scrapy-redis所有request爬取完畢,如何解決爬蟲空跑問題?

1. 背景

這裡寫圖片描述
根據scrapy-redis分散式爬蟲的原理,多臺爬蟲主機共享一個爬取佇列。當爬取佇列中存在request時,爬蟲就會取出request進行爬取,如果爬取佇列中不存在request時,爬蟲就會處於等待狀態,行如下:

E:\Miniconda\python.exe E:/PyCharmCode/redisClawerSlaver/redisClawerSlaver/spiders/main.py
2017-12-12 15:54:18 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapybot)
2017-12-12 15:54:18 [scrapy.utils.log] INFO: Overridden settings: {'SPIDER_LOADER_WARN_ONLY': True}
2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.logstats.LogStats']
2017-12-12 15:54:18 [myspider_redis] INFO: Reading start URLs from redis key 'myspider:start_urls' (batch size: 110, encoding: utf-8
2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'redisClawerSlaver.middlewares.ProxiesMiddleware',
 'redisClawerSlaver.middlewares.HeadersMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-12 15:54:18 [scrapy.middleware] INFO: Enabled item pipelines:
['redisClawerSlaver.pipelines.ExamplePipeline',
 'scrapy_redis.pipelines.RedisPipeline']
2017-12-12 15:54:18 [scrapy.core.engine] INFO: Spider opened
2017-12-12 15:54:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-12 15:55:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-12 15:56:18 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
  •  
  • 可是,如果所有的request都已經爬取完畢了呢?這件事爬蟲程式是不知道的,它無法區分結束和空窗期狀態的不同,所以會一直處於上面的那種等待狀態,也就是我們說的空跑。
  • 那有沒有辦法讓爬蟲區分這種情況,自動結束呢?

2. 環境

  • 系統:win7
  • scrapy-redis
  • redis 3.0.5
  • python 3.6.1

3. 解決方案

  • 從背景介紹來看,基於scrapy-redis分散式爬蟲的原理,爬蟲結束是一個很模糊的概念,在爬蟲爬取過程中,爬取佇列是一個不斷動態變化的過程,隨著request的爬取,又會有新的request進入爬取佇列。進進出出。爬取速度高於填充速度,就會有佇列空窗期(爬取佇列中,某一段時間會出現沒有request的情況),爬取速度低於填充速度,就不會出現空窗期。
    所以對於爬蟲結束這件事來說,只能模糊定義,沒有一個精確的標準。
  • 所以,下面這兩種方案都是一種大概的思路。

3.1. 利用scrapy的關閉spider擴充套件功能

# 關閉spider擴充套件
class scrapy.contrib.closespider.CloseSpider
當某些狀況發生,spider會自動關閉。每種情況使用指定的關閉原因。

關閉spider的情況可以通過下面的設定項配置:

CLOSESPIDER_TIMEOUT
CLOSESPIDER_ITEMCOUNT
CLOSESPIDER_PAGECOUNT
CLOSESPIDER_ERRORCOUNT
  •  
  • CLOSESPIDER_TIMEOUT
CLOSESPIDER_TIMEOUT
預設值: 0

一個整數值,單位為秒。如果一個spider在指定的秒數後仍在執行, 它將以 closespider_timeout 的原因被自動關閉。 如果值設定為0(或者沒有設定),spiders不會因為超時而關閉。
  •  
  • CLOSESPIDER_ITEMCOUNT
CLOSESPIDER_ITEMCOUNT
預設值: 0

一個整數值,指定條目的個數。如果spider爬取條目數超過了指定的數, 並且這些條目通過item pipeline傳遞,spider將會以 closespider_itemcount 的原因被自動關閉。
  •  
  • CLOSESPIDER_PAGECOUNT
CLOSESPIDER_PAGECOUNT
0.11 新版功能.

預設值: 0

一個整數值,指定最大的抓取響應(reponses)數。 如果spider抓取數超過指定的值,則會以 closespider_pagecount 的原因自動關閉。 如果設定為0(或者未設定),spiders不會因為抓取的響應數而關閉。
  •  
  • CLOSESPIDER_ERRORCOUNT
CLOSESPIDER_ERRORCOUNT
0.11 新版功能.

預設值: 0

一個整數值,指定spider可以接受的最大錯誤數。 如果spider生成多於該數目的錯誤,它將以 closespider_errorcount 的原因關閉。 如果設定為0(或者未設定),spiders不會因為發生錯誤過多而關閉。
  •  
  • 示例:開啟 settings.py,新增一個配置項,如下
# 爬蟲執行超過23.5小時,如果爬蟲還沒有結束,則自動關閉
CLOSESPIDER_TIMEOUT = 84600
  •  
  • 特別注意:如果爬蟲在規定時限沒有把request全部爬取完畢,此時強行停止的話,爬取佇列中就還會存有部分request請求。那麼爬蟲下次開始爬取時,一定要記得在master端對爬取佇列進行清空操作。
  • 另外如果是分散式爬蟲,先確認幾臺機器同時跑,拿CLOSESPIDER_ITEMCOUNT來說,比如要拿100條資料,10臺機器一起跑,那麼CLOSESPIDER_ITEMCOUNT=10即可

 

第二種方案:改scrapy_redis的原始碼,不適合分散式部署