一:前言
正常情況下使用scrapy-redis 做分布式使用,這個比較方便簡單,但是有個問題:當redis調度隊列中沒有新增request 也不會讓spider停止。如果只是使用少量爬蟲服務器那還不會影響太大,如果爬蟲用的服務器很多,這將造成大量資源的浪費,并且影響服務器上其他爬蟲的速度。整理了一下資源記錄一下,方便使用。
二:解決方案
Scrapy 中有個信號工具可以幫助解決這個問題。利用信號中的 spider_idle
spider_idle
當spider進入空閑(idle)狀態(tài)時該信號被發(fā)送。空閑意味著:
- requests正在等待被下載
- requests被調度
- items正在item pipeline中被處理
一旦空閑就會發(fā)送該信號,所以我們就收集這個信號,當空閑時間達到我們的設定值就會讓spider停止。
三:實例代碼
scrapy_redis_extension.py
# -*- coding: utf-8 -*-
import logging
import time
from scrapy import signals
class RedisSpiderClosedExensions(object):
def __init__(self, idle_number, crawler):
self.crawler = crawler
self.idle_number = idle_number
self.idle_list = []
self.idle_count = 0
@classmethod
def from_crawler(cls, crawler):
# IDLE_NUMBER目前被被設定為等待時間,IDLE一個時間片5秒,所以setting.py中設置的時間除以5就是時間片的數(shù)量
idle_number = crawler.settings.getint('IDLE_TIME', 600) // 5
ext = cls(idle_number, crawler)
crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened)
crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
crawler.signals.connect(ext.spider_idle, signal=signals.spider_idle)
return ext
def spider_opened(self, spider):
logger.info("opened spider %s redis spider Idle, Continuous idle limit: %d", spider.name, self.idle_number)
def spider_closed(self, spider):
logger.info("closed spider %s, idle count %d , Continuous idle count %d",
spider.name, self.idle_count, len(self.idle_list))
def spider_idle(self, spider):
self.idle_count += 1
self.idle_list.append(time.time())
idle_list_len = len(self.idle_list)
if idle_list_len > 2 and self.idle_list[-1] - self.idle_list[-2] > 6:
self.idle_list = [self.idle_list[-1]]
elif idle_list_len > self.idle_number:
logger.info('\n continued idle number exceed {} Times'
'\n meet the idle shutdown conditions, will close the reptile operation'
'\n idle start time: {}, close spider time: {}'.format(self.idle_number,
self.idle_list[0], self.idle_list[0]))
self.crawler.engine.close_spider(spider, 'closespider_pagecount')
五:說明
如果把這個擴展放到python環(huán)境里面,比如 /Anaconda3\Lib\site-packages,這樣再使用的時候就非常方便了。需要用的時候就在設置里面設置一個最大空閑時間,如果沒有設置默認就是10分鐘,然后 EXTENSIONS 擴展里面加入這個包的引入
setting.py 修改如下:
# redis 空跑時間 秒
IDLE_TIME= 600
# 同時擴展里面加入這個
EXTENSIONS = {
'scrapy_redis_extension.RedisSpiderClosedExensions': 500,
}