解决 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秒就能跑完,你可以在此基础上做一些判断。原理一样,大家可以照葫芦画瓢。
解决 Scrapy-Redis 空跑问题,链接跑完后自动关闭爬虫的更多相关文章
- 解决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 ...
- Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方
Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方案 >>>>>>>>>>>>>> ...
- ETL过程跑完后,使用python发送邮件
目标库中,如果有行数为0的表,使用python发送邮件 # -*- coding:utf-8 -*- # Author: zjc # Description:send monitor info to ...
- 六、SQL语句进行多条件查询,并解决参数为空的情况
一.SQL语句进行多条件查询,并解决参数为空的情况 QueryEntity query; var whereSql = new StringBuilder("Where 1=1") ...
- Redis ASP.NET 配置链接
对于安装Redis后 很是不明白如何建立Redis 和 .net 的链接配置 于是查找了很多的资料 首先第一步:安装ASP.NET NuGet 包 (ServiceStack.Redis) 安装好后 ...
- 解决---MISCONF Redis被配置为保存RDB快照,但目前无法在磁盘上存留。可能修改数据集的命令被禁用。请检查Redis日志,了解有关错误的详细信息。
解决---MISCONF Redis被配置为保存RDB快照,但目前无法在磁盘上存留.可能修改数据集的命令被禁用.请检查Redis日志,了解有关错误的详细信息. 出现bug: 在学习celery,将数据 ...
- 【解决】 新浪sae固定链接404 问题
固定链接404 固定链接是一个很重要的内容,wordpress默认的链接很复杂,也不利于搜索引擎搜索.wordpress也提供修改固定链接的功能,在设置里面[固定链接]修改. 但是,使用新浪sae的小 ...
- C# LIstbox 解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题
解决WinForm下ListBox控件“设置DataSource属性后无法修改项集合”的问题 分类: winform2008-05-24 02:33 2592人阅读 评论(11) 收藏 举报 winf ...
- appium 链接真机后,运行代码,但是APP并没有启动
要淡定,链接真机后,问题一下多出来这么多,还没有启动程序,就碰到接二连三的问题. 爽到家了.慢慢解决吧. 具体问题是这样的: # coding=utf-8from appium import webd ...
随机推荐
- 存储引擎-Buffered tree
Buffered-tree 也称为COLA,即cache-oblivious,可以不需要知道具体内存大小和一个块的大小,使用一套逻辑进行处理,因此内存大小可知,内存可能被临时占用去做其它事情. Buf ...
- javascript中如何让类工厂和构造函数变成同一个函数
我们知道在js中可以用一个函数来定义对象的类,该函数称之为对象的构造函数,我们在需要create对象的时候直接调用这个构造函数即可: var Man = funciton(name){ this.na ...
- 熊猫猪新系统测试之一:Windows 10 技术预览版
话说本猫不用windows很多年了呀!不过看到微软最新的Windows10还是手痒了,想安装体验一把.于是第一时间下载,并做成usb引导安装镜像,在08年的老台式机上安装尝鲜鸟.下载ISO和安装方法这 ...
- 深入浅出理解python 装饰器
之前就了解到了装饰器, 但是就会点皮毛, 而且对其调用方式感到迷茫,正好现在的项目我想优化,就想到了用装饰器, 因此深入研究了下装饰器.先看下代码: import time # 将函数作为参数传入到此 ...
- search for a range(找出一个数在数组中开始和结束位置)
Given an array of integers sorted in ascending order, find the starting and ending position of a giv ...
- SQL Server复制表结构和表数据生成新表的语句
参考:http://topic.csdn.net/t/20020621/09/820025.html SELECT * INTO newTableName FROM oldTabl ...
- 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 ...
- Manacher算法解析
Manacher算法 Manachar算法主要是处理字符串中关于回文串的问题的,它可以在 O(n) 的时间处理出以字符串中每一个字符为中心的回文串半径,由于将原字符串处理成两倍长度的新串,在每两个字符 ...
- unity零基础开始学习做游戏(六)背景给我“滚”~
-------小基原创,转载请给我一个面子 一望无际的...空旷场景,看着实在是难受,不如添加些背景吧.如果要真的想好好设计关卡背景的话,最好是做一个地图编辑器,不过做开发工具毕竟有点点复杂且枯燥,以 ...
- python中的类
以下内容是python tutorial的读书笔记: 一.命名空间的分层 二.local赋值语句,nonlocal和global的区别 local赋值语句,它是无法实现对于最里层的作用域的重新绑定的 ...