Scrapy-Redis 空跑问题,redis_key链接跑完后,自动关闭爬虫

问题:
scrapy-redis框架中,reids存储的xxx:requests已经爬取完毕,但程序仍然一直运行,如何自动停止程序,结束空跑。

分布式扩展:

我们知道 scrapy 默认是单机运行的,那么scrapy-redis是如何把它变成可以多台机器协作的呢?

首先解决爬虫等待,不被关闭的问题:

1、scrapy内部的信号系统会在爬虫耗尽内部队列中的request时,就会触发spider_idle信号。

2、爬虫的信号管理器收到spider_idle信号后,将调用注册spider_idle信号的处理器进行处理。

3、当该信号的所有处理器(handler)被调用后,如果spider仍然保持空闲状态, 引擎将会关闭该spider。

scrapy-redis 中的解决方案 在信号管理器上注册一个对应在spider_idle信号下的spider_idle()方法,当spider_idle触发是,信号管理器就会调用这个爬虫中的spider_idle(), Scrapy_redis 源码如下:

def spider_idle(self):
        """Schedules a request if available, otherwise waits."""
        # XXX: Handle a sentinel to close the spider.
        self.schedule_next_requests()    # 这里调用schedule_next_requests() 来从redis中生成新的请求
        raise DontCloseSpider              # 抛出不要关闭爬虫的DontCloseSpider异常,保证爬虫活着

解决思路:

通过前面的了解,我们知道 爬虫关闭的关键是 spider_idle 信号。
spider_idle信号只有在爬虫队列为空时才会被触发, 触发间隔为5s。
那么我们也可以使用同样的方式,在信号管理器上注册一个对应在spider_idle信号下的spider_idle()方法。
在 spider_idle() 方法中,编写结束条件来结束爬虫

解决方案:
redis_key 为空后一段时间关闭爬虫

redis_key 为空后一段时间关闭爬虫 的实现方案:

这里在 Scrapy 中的 exensions(扩展) 中实现,当然你也可以在pipelines(管道)中实现。

扩展框架提供一个机制,使得你能将自定义功能绑定到Scrapy。 扩展只是正常的类,它们在Scrapy启动时被实例化、初始化。 关于扩展详细见: scrapy 扩展(Extensions)

    • 在settings.py 文件的目录下,创建一个名为 extensions.py 的文件,
    • 在其中写入以下代码
# -*- coding: utf-8 -*-
# Define here the models for your scraped Extensions
import logging
import time
from scrapy import signals
from scrapy.exceptions import NotConfigured
logger = logging.getLogger(__name__)

class RedisSpiderSmartIdleClosedExensions(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):
        # 首先检查是否应该启用和提高扩展
        # 否则不配置
        if not crawler.settings.getbool('MYEXT_ENABLED'):
            raise NotConfigured

        # 获取配置中的时间片个数,默认为360个,30分钟
        idle_number = crawler.settings.getint('IDLE_NUMBER', 360)

        # 实例化扩展对象
        ext = cls(idle_number, crawler)

        # 将扩展对象连接到信号, 将signals.spider_idle 与 spider_idle() 方法关联起来。
        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 the extension object
        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())       # 每次触发 spider_idle时,记录下触发时间戳
        idle_list_len = len(self.idle_list)         # 获取当前已经连续触发的次数

        # 判断 当前触发时间与上次触发时间 之间的间隔是否大于5秒,如果大于5秒,说明redis 中还有key
        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')
  • 在settings.py 中添加以下配置, 请将 lianjia_ershoufang 替换为你的项目目录名。

    MYEXT_ENABLED=True      # 开启扩展
    IDLE_NUMBER=360           # 配置空闲持续时间单位为 360个 ,一个时间单位为5s
    
    # 在 EXTENSIONS 配置,激活扩展
    'EXTENSIONS'= {
                'lianjia_ershoufang.extensions.RedisSpiderSmartIdleClosedExensions': 500,
            },
  • 完成空闲关闭扩展,爬虫会在持续空闲 360个时间单位后关闭爬虫

配置说明:

MYEXT_ENABLED: 是否启用扩展,启用扩展为 True, 不启用为 False
IDLE_NUMBER: 关闭爬虫的持续空闲次数,持续空闲次数超过IDLE_NUMBER,爬虫会被关闭。默认为 360 ,也就是30分钟,一分钟12个时间单位

结语

此方法只使用于 5秒内跑不完一组链接的情况,如果你的一组链接5秒就能跑完,你可以在此基础上做一些判断。原理一样,大家可以照葫芦画瓢。

解决 Scrapy-Redis 空跑问题,链接跑完后自动关闭爬虫的更多相关文章

  1. 解决scrapy fetch http://www.csdn.net ModuleNotFoundError No module named 'win32api'和ImportError DLL load failed找不到指定的模块

    1.解决scrapy fetch http://www.csdn.netModuleNotFoundError No module named 'win32api' Python是没有自带访问wind ...

  2. Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方

    Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方案 >>>>>>>>>>>>>> ...

  3. ETL过程跑完后,使用python发送邮件

    目标库中,如果有行数为0的表,使用python发送邮件 # -*- coding:utf-8 -*- # Author: zjc # Description:send monitor info to ...

  4. 六、SQL语句进行多条件查询,并解决参数为空的情况

    一.SQL语句进行多条件查询,并解决参数为空的情况 QueryEntity query; var whereSql = new StringBuilder("Where 1=1") ...

  5. Redis ASP.NET 配置链接

    对于安装Redis后 很是不明白如何建立Redis 和 .net 的链接配置 于是查找了很多的资料 首先第一步:安装ASP.NET  NuGet 包 (ServiceStack.Redis) 安装好后 ...

  6. 解决---MISCONF Redis被配置为保存RDB快照,但目前无法在磁盘上存留。可能修改数据集的命令被禁用。请检查Redis日志,了解有关错误的详细信息。

    解决---MISCONF Redis被配置为保存RDB快照,但目前无法在磁盘上存留.可能修改数据集的命令被禁用.请检查Redis日志,了解有关错误的详细信息. 出现bug: 在学习celery,将数据 ...

  7. 【解决】 新浪sae固定链接404 问题

    固定链接404 固定链接是一个很重要的内容,wordpress默认的链接很复杂,也不利于搜索引擎搜索.wordpress也提供修改固定链接的功能,在设置里面[固定链接]修改. 但是,使用新浪sae的小 ...

  8. C# LIstbox 解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题

    解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题 分类: winform2008-05-24 02:33 2592人阅读 评论(11) 收藏 举报 winf ...

  9. appium 链接真机后,运行代码,但是APP并没有启动

    要淡定,链接真机后,问题一下多出来这么多,还没有启动程序,就碰到接二连三的问题. 爽到家了.慢慢解决吧. 具体问题是这样的: # coding=utf-8from appium import webd ...

随机推荐

  1. 存储引擎-Buffered tree

    Buffered-tree 也称为COLA,即cache-oblivious,可以不需要知道具体内存大小和一个块的大小,使用一套逻辑进行处理,因此内存大小可知,内存可能被临时占用去做其它事情. Buf ...

  2. javascript中如何让类工厂和构造函数变成同一个函数

    我们知道在js中可以用一个函数来定义对象的类,该函数称之为对象的构造函数,我们在需要create对象的时候直接调用这个构造函数即可: var Man = funciton(name){ this.na ...

  3. 熊猫猪新系统测试之一:Windows 10 技术预览版

    话说本猫不用windows很多年了呀!不过看到微软最新的Windows10还是手痒了,想安装体验一把.于是第一时间下载,并做成usb引导安装镜像,在08年的老台式机上安装尝鲜鸟.下载ISO和安装方法这 ...

  4. 深入浅出理解python 装饰器

    之前就了解到了装饰器, 但是就会点皮毛, 而且对其调用方式感到迷茫,正好现在的项目我想优化,就想到了用装饰器, 因此深入研究了下装饰器.先看下代码: import time # 将函数作为参数传入到此 ...

  5. search for a range(找出一个数在数组中开始和结束位置)

    Given an array of integers sorted in ascending order, find the starting and ending position of a giv ...

  6. SQL Server复制表结构和表数据生成新表的语句

    参考:http://topic.csdn.net/t/20020621/09/820025.html SELECT   *   INTO   newTableName   FROM   oldTabl ...

  7. The note of Developing Innovative Ideas for New Companies Course

    This course is free on the Coursera Site,But it only has English version Threee pieces of the course ...

  8. Manacher算法解析

    Manacher算法 Manachar算法主要是处理字符串中关于回文串的问题的,它可以在 O(n) 的时间处理出以字符串中每一个字符为中心的回文串半径,由于将原字符串处理成两倍长度的新串,在每两个字符 ...

  9. unity零基础开始学习做游戏(六)背景给我“滚”~

    -------小基原创,转载请给我一个面子 一望无际的...空旷场景,看着实在是难受,不如添加些背景吧.如果要真的想好好设计关卡背景的话,最好是做一个地图编辑器,不过做开发工具毕竟有点点复杂且枯燥,以 ...

  10. python中的类

    以下内容是python tutorial的读书笔记: 一.命名空间的分层 二.local赋值语句,nonlocal和global的区别 local赋值语句,它是无法实现对于最里层的作用域的重新绑定的 ...