Scrapy 扩展:解决scrapy-redis 调度空跑问题
2018-08-08 本文已影响15人
梅花鹿数据rieuse
一:前言
正常情况下使用scrapy-redis 做分布式使用,这个比较方便简单,但是有个问题:当redis调度队列中没有新增request 也不会让spider停止。如果只是使用少量爬虫服务器那还不会影响太大,如果爬虫用的服务器很多,这将造成大量资源的浪费,并且影响服务器上其他爬虫的速度。整理了一下资源记录一下,方便使用。
二:解决方案
Scrapy 中有个信号工具可以帮助解决这个问题。利用信号中的 spider_idle
spider_idle
当spider进入空闲(idle)状态时该信号被发送。空闲意味着:
- requests正在等待被下载
- requests被调度
- items正在item pipeline中被处理
一旦空闲就会发送该信号,所以我们就收集这个信号,当空闲时间达到我们的设定值就会让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就是时间片的数量
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环境里面,比如 /Anaconda3\Lib\site-packages,这样再使用的时候就非常方便了。需要用的时候就在设置里面设置一个最大空闲时间,如果没有设置默认就是10分钟,然后 EXTENSIONS 扩展里面加入这个包的引入
setting.py 修改如下:
# redis 空跑时间 秒
IDLE_TIME= 600
# 同时扩展里面加入这个
EXTENSIONS = {
'scrapy_redis_extension.RedisSpiderClosedExensions': 500,
}