You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scrapy爬虫被终止时触发函数更新Redis状态?

问题解答

核心结论

  • SIGKILL信号无法被捕获:操作系统会直接强制终止进程,不会给进程留下任何处理时间,因此没法通过Scrapy信号或Python信号处理函数响应这类中断。
  • 可处理的中断场景:对于SIGTERM、SIGINT(比如Ctrl+C触发)这类可捕获的信号,可以通过Scrapy内置信号或Python原生信号机制来更新Redis中的状态。

具体实现方案

1. 利用Scrapy内置信号处理可控停止

Scrapy提供了engine_stopped、spider_closed等信号,可覆盖爬虫正常结束、被SIGTERM终止等场景:

from scrapy import signals

class YourSpider(scrapy.Spider):
    name = "your_spider"

    def spider_interrupted(self):
        # 更新Redis中的爬虫状态为“停止”
        redis_client.set("spider:status", "停止")
        redis_client.save()

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super().from_crawler(crawler, *args, **kwargs)
        # 连接信号与处理函数
        crawler.signals.connect(spider.spider_interrupted, signal=signals.engine_stopped)
        crawler.signals.connect(spider.spider_interrupted, signal=signals.spider_closed)
        return spider

2. 用Python原生信号处理捕获系统中断

针对SIGTERM、SIGINT这类可捕获信号,也可以直接通过Python的signal模块注册处理逻辑:

import signal
import redis

redis_client = redis.Redis(host='localhost', port=6379, db=0)

def update_spider_status(signum, frame):
    # 更新Redis状态
    redis_client.set("spider:status", "停止")
    # 重新绑定默认信号处理,确保进程能正常终止
    signal.signal(signum, signal.SIG_DFL)
    raise KeyboardInterrupt

# 注册信号处理
signal.signal(signal.SIGTERM, update_spider_status)
signal.signal(signal.SIGINT, update_spider_status)

3. SIGKILL的兜底监控方案

由于SIGKILL无法被进程自身捕获,只能通过外部监控机制弥补:

  • 在Django应用中定时轮询爬虫进程的存活状态(通过进程ID)
  • 一旦检测到进程不存在,立即更新Redis中的爬虫状态为“停止”

注意事项

  • 确保Redis操作的原子性,避免状态更新失败
  • 外部轮询的间隔不宜过短,防止给服务器造成额外压力
  • 同时结合Scrapy信号与Python信号处理,覆盖更多停止场景

内容的提问来源于stack exchange,提问作者user5329403

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:08:16