Scrapy 扩展:解决scrapy-redis 调度空跑问题

一:前言

正常情况下使用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,
}
    原文作者:rieuse
    原文地址: https://www.jianshu.com/p/ba010b805cea
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞