Scrapy定时关闭

之前转载过一篇介绍定时执行Scrapy方法的博文:scrapy定时执行抓取任务,并且一直在使用这个方法做增量爬虫。

但是问题来了,假设如下情景:某一天,我要爬的网站更新了非常非常多的内容,以至于一天过去了,我的爬虫还没有停止工作。但是我的Ubuntu系统并不知道,于是它又定时的去crontab中执行了定时任务。于是就出现了如下尴尬的情景:

我的系统里同时运行着两只有同样功能的爬虫。

这太尴尬了,即浪费系统资源,又得不到什么好的效果,还给别人的服务器造成双倍的负担。

所以,如果有什么办法能保证爬虫在第二天开启前已经关闭就好了。

怎么说,Scrapy这框架,很舒服。只需要配置一个扩展就好了,打开settings.py,添加一个配置项:

CLOSESPIDER_TIMEOUT = 82800 # 23小时后结束爬虫

这个配置项的意思:

CLOSESPIDER_TIMEOUT

默认值: 0

一个整数值,单位为秒。如果一个spider在指定的秒数后仍在运行, 它将以 closespider_timeout 的原因被自动关闭。 如果值设置为0(或者没有设置),spiders不会因为超时而关闭。

配好了之后,我们的增量爬虫就可以每天运行23小时,休息一小时,继续工作,这样周而往复了。

相关的扩展还有很多,比如可以配置获得了一定数量的item则退出等等,详见文档扩展(Extensions)

<think> 我们正在讨论Scrapy框架中的扩展中间件。根据之前的对话,用户已经了解Scrapy有四种核心中间件类型:爬虫中间件、下载器中间件、扩展中间件(Extensions)和项目管道(Item Pipelines)。现在用户特别询问关于自定义扩展中间件的方法和示例。 扩展中间件(Extensions)是通过Scrapy的信号系统(signals)来工作的,它们可以在Scrapy运行的各个阶段插入自定义逻辑。创建自定义扩展需要以下步骤: 1. **定义扩展类**:创建一个类,并实现必要的方法。 2. **连接到信号**:在类中连接到Scrapy的各种信号(例如`spider_opened`, `spider_closed`等)。 3. **注册扩展**:在Scrapy的配置文件中启用扩展。 下面是一个自定义扩展的示例,该扩展在爬虫启动和关闭时打印日志,并在爬虫运行期间定期打印统计信息(模拟定时监控功能): ```python import logging from scrapy import signals from scrapy.exceptions import NotConfigured logger = logging.getLogger(__name__) class MyExtension: """自定义扩展,用于监控爬虫运行状态""" def __init__(self, stats, interval=60.0): # 初始化统计信息和间隔时间 self.stats = stats self.interval = interval # 定时任务句柄 self.task = None @classmethod def from_crawler(cls, crawler): # 获取配置中的间隔时间,如果没有配置则使用默认值60秒 interval = crawler.settings.getfloat('MYEXT_INTERVAL', 60.0) # 如果扩展未启用,则抛出异常 if not crawler.settings.getbool('MYEXT_ENABLED', True): raise NotConfigured # 创建扩展实例 ext = cls(crawler.stats, interval) # 连接信号 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def spider_opened(self, spider): """爬虫启动时执行""" logger.info(f"Spider opened: {spider.name}") # 启动定时任务 from twisted.internet import task self.task = task.LoopingCall(self.log_stats, spider) self.task.start(self.interval) def log_stats(self, spider): """定时记录统计信息""" stats = self.stats.get_stats() logger.info(f"Spider {spider.name} stats: {stats}") def spider_closed(self, spider): """爬虫关闭时执行""" logger.info(f"Spider closed: {spider.name}") # 停止定时任务 if self.task and self.task.running: self.task.stop() ``` 在项目的`settings.py`中启用该扩展: ```python EXTENSIONS = { 'myproject.extensions.MyExtension': 500, # 优先级设为500 } MYEXT_ENABLED = True # 默认已启用,此项可省略 MYEXT_INTERVAL = 30.0 # 设置间隔时间为30秒 ``` 这个扩展做了以下事情: - 在爬虫启动时开始一个定时任务,每隔一段时间(通过`MYEXT_INTERVAL`设置)打印一次统计信息。 - 在爬虫关闭时停止定时任务。 注意: - 扩展类必须实现`from_crawler`类方法,用于创建扩展实例并连接信号。 - 使用`crawler.signals.connect`来连接信号处理函数。 - 扩展的执行顺序由`EXTENSIONS`设置中的优先级数值决定(数值越小越先执行)。 通过这种方式,我们可以轻松地扩展Scrapy的功能,例如实现监控、报警、资源清理等。 §§相关问题§§ 1. Scrapy扩展中间件如何接入外部监控系统(如Prometheus)? 2. 如何在Scrapy扩展中处理异常并发送警报? 3. Scrapy的信号系统支持哪些关键生命周期事件? </think> ### Scrapy自定义扩展中间件方法与示例 在Scrapy框架中,自定义扩展中间件(Extensions)是通过订阅**事件系统(signals)**实现的全局功能增强组件。它不属于请求/响应流水线,但能访问Scrapy核心对象(如crawler、stats),常用于监控、通知等场景。 #### 创建方法 1. **定义扩展类** 需实现`from_crawler`类方法和事件处理方法: ```python from scrapy import signals class MyExtension: def __init__(self, crawler): self.crawler = crawler @classmethod def from_crawler(cls, crawler): ext = cls(crawler) # 订阅事件 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def spider_opened(self, spider): print(f"爬虫启动: {spider.name}") def spider_closed(self, spider, reason): print(f"爬虫关闭: {spider.name}, 原因: {reason}") ``` 2. **注册扩展** 在`settings.py`中激活: ```python EXTENSIONS = { 'myproject.extensions.MyExtension': 500, # 数值表示优先级 } ``` #### 实用示例 **定时性能监控扩展** 每60秒记录爬虫状态: ```python from twisted.internet import task class StatsMonitorExtension: def __init__(self, crawler): self.stats = crawler.stats self.interval = 60 # 秒 self.task = None @classmethod def from_crawler(cls, crawler): ext = cls(crawler) crawler.signals.connect(ext.spider_opened, signals.spider_opened) crawler.signals.connect(ext.spider_closed, signals.spider_closed) return ext def spider_opened(self, spider): self.task = task.LoopingCall(self.log_stats, spider) self.task.start(self.interval) def log_stats(self, spider): stats_data = { "pages": self.stats.get_value('response_received_count', 0), "items": self.stats.get_value('item_scraped_count', 0), "errors": self.stats.get_value('log_count/ERROR', 0) } print(f"[监控] {spider.name}状态: {stats_data}") def spider_closed(self, spider, reason): if self.task and self.task.running: self.task.stop() ``` #### 关键特性 1. **事件订阅机制**: - `engine_started`/`engine_stopped`:引擎启停 - `spider_opened`/`spider_closed`:爬虫启停 - `item_scraped`:数据项抓取成功 - `item_dropped`:数据项被丢弃[^3] 2. **核心对象访问**: ```python def from_crawler(cls, crawler): # 获取配置 interval = crawler.settings.getfloat('STATS_INTERVAL', 60) # 访问统计收集器 stats = crawler.stats # 访问爬虫配置 spider_settings = crawler.spider.settings ``` 3. **执行优先级控制** 通过`EXTENSIONS`字典的值调整顺序(值越小优先级越高)[^1] ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孔天逸

没有钱用,只能写写博客这样子~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值