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

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秒就能跑完,你可以在此基础上做一些判断。原理一样,大家可以照葫芦画瓢。

原文地址:https://www.cnblogs.com/zhouxinfei/p/8593155.html

时间: 2024-10-31 11:32:52

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

解决scrapy fetch http://www.csdn.net ModuleNotFoundError No module named 'win32api'

1.解决scrapy fetch http://www.csdn.netModuleNotFoundError No module named 'win32api' Python是没有自带访问windows系统API的库的,需要下载.库的名称叫pywin32,可以从网上直接下载. 以下链接地址可以下载:http://sourceforge.net/projects/pywin32/files%2Fpywin32/ (下载适合你的python版本) 解决scrapy fetch http://ww

湖南房卡跑胡子棋牌源码,娄底跑胡子\衡阳跑胡子\怀化跑胡子\湘乡跑胡子

湖南房卡跑胡子棋牌源码,包括(娄底跑胡子\衡阳跑胡子\怀化跑胡子\湘乡跑胡子\涟源跑胡子. 我们的源码都是大公司来源,经过公司技术团队多次修改,多次测试的,直接拿去给客户定制的源码,源码非常完整,优化的非常好,运行起来非常流程和完美.1.客户端源码是基于cocos2d版本开发的.代码完整可编译.亲测在WINDOWS平台下成功编译.2.编译环境: windows7(64位) + cocos3.13.1 + ndk13 + ant1.9.7 + python2.7.5 + android-sdk(2

CentOS+Apache+php无法访问redis的解决方法 Redis server went away

在CentOS下配置Apache+php+redis+phpredis环境.编辑访问redis缓存的php程序test.php,以应用程序方式在后台运行,可成功访问Redis,而在Apache下以网页形式访问时则出错,在访问Redis以及之后的代码均不再执行.查看Apache的日志:/var/log/httpd/error_log,发现代码运行时出现异常:PHP Fatal error: Uncaught exception 'RedisException' with message 'Redi

sql server2008 搭建链接服务器成功后查询时报Cannot obtain the schema rowset "DBSCHEMA_TABLES_INFO" for OLE DB provider "SQLNCLI10" for linked server "XXXXX". 的解决方法

原文:sql server2008 搭建链接服务器成功后查询时报Cannot obtain the schema rowset "DBSCHEMA_TABLES_INFO" for OLE DB provider "SQLNCLI10" for linked server "XXXXX". 的解决方法 这是由于链接的数据库服务器的版本与本地数据库服务器不一致,有人说要升到sp3,sp4,然后在执行什么语句之类的 我觉得太繁琐了,通过网上查询之后看

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

Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方案 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ?Copyright 蕃薯耀 2017年7月22日 http://www.cnblogs.com/fanshuyao/ 一.问题说明 在Linux系统中,Redi

解决Scrapy shell启动出现UnicodeEncodeError问题

windows 命令行编码是cp936,而D:\Python27\Scripts\scrapy脚本编码是Unicode编码顾在命令行启动会出现编码问题 解决办法:修改D:\Python27\Scripts\ 下的scrapy文件,这个文件即scrapy命令的程序文件,加上如下代码即可: import sysdefault_encoding = 'cp936'if sys.getdefaultencoding() != default_encoding: reload(sys) sys.setde

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

目标库中,如果有行数为0的表,使用python发送邮件 # -*- coding:utf-8 -*- # Author: zjc # Description:send monitor info to someone. # Date: 20170718 import contextlib import pymysql import smtplib from email.mime.text import MIMEText # 监控信息变量 TABLE_SCHEMA_LIST = ('db-name1

解决MFC应用程序在调整系统比列放大后出错问题心得

公司有一个屏幕书写的软件,06年开始开发的,至今已八年之久,目前处于维护阶段,在接到这个任务前我也没机会接触这个项目的代码 日前,客户反应在系统比列调整为150%出现界面显示不正常.笔记偏移.笔记画出屏幕崩溃等问题.更坑人的是,经过测试部测试发现在不同的主机上有不同的现象,后来在我的自己的开发机上运行有问题,但是比较少.因为我现任的直属领导就是当前这个项目的主力之一,他也觉得很诡异,让我更诡异的是他居然帮这个任务交给了我. 好吧,硬着头皮上吧,花了三天时间来熟悉代码和软件,在这个过程中发现有时重

[解决]IP地址非法,请接入联通热点后重新获取

在使用联通chinaunicom WLAN上网时,在弹出的登陆界面后输入账号.密码,点登陆,显示IP地址非法,请接入联通热点后重新获取.现在在其他地方看到解决办法连接chinaunicom,弹出登陆界面后,不要输入账号.密码,在弹出的登陆界面里找***10010.com,点一下这个网址,然后再输入账号.密码,点登陆就可以了本人已试过,用此方法就可以使用联通的WLAN上网了 http://bbs.dospy.com/viewthread.php?tid=16421996&bbsid=575