如何实现Scrapy运行指定时长后暂停,按下任意键恢复?
Scrapy定时暂停并等待按键恢复的实现方案
问题分析
你当前的代码存在两个核心问题:
- 定时器线程中调用
input()只会阻塞该线程,无法暂停Scrapy主线程的爬虫逻辑——Scrapy引擎运行在独立主线程中,线程间的阻塞互不影响。 - 未使用Scrapy官方提供的引擎控制接口实现暂停/恢复,而是试图通过线程阻塞实现,不符合Scrapy的工作机制。
解决方案
利用Scrapy原生的crawler.engine.pause()和crawler.engine.resume()方法控制爬虫状态,结合独立线程处理按键输入,避免阻塞主线程。以下是完整实现代码:
完整中间件代码
from scrapy import signals from threading import Timer, Thread import subprocess import sys import termios import tty class RepeatTimer(Timer): def run(self): while not self.finished.wait(self.interval): self.function(*self.args, **self.kwargs) CMD = ''' on run argv display notification (item 2 of argv) with title (item 1 of argv) end run ''' class PauseOnTimerMiddleware: def __init__(self): self.timer = None self.crawler = None def notify(self, title, text): # 发送系统通知 subprocess.call(['osascript', '-e', CMD, title, text]) # 暂停Scrapy引擎 self.crawler.engine.pause() print("\nScrapy已暂停,按下任意键恢复运行...") # 启动独立线程等待按键,避免阻塞主线程 Thread(target=self.wait_for_key).start() def wait_for_key(self): # 保存终端原有配置 old_settings = termios.tcgetattr(sys.stdin) try: # 设置终端为原始模式,捕获任意按键(无需回车) tty.setcbreak(sys.stdin.fileno()) # 读取单个按键 sys.stdin.read(1) # 恢复Scrapy引擎 self.crawler.engine.resume() print("\nScrapy已恢复运行") finally: # 恢复终端原有配置,避免终端异常 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings) @classmethod def from_crawler(cls, crawler): s = cls() s.crawler = crawler crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) crawler.signals.connect(s.spider_closed, signal=signals.spider_closed) return s def spider_opened(self, spider): # 启动定时任务,此处设置为40秒触发一次 self.timer = RepeatTimer(40, self.notify, args=("GetBooks Timer", "Change Your IP Address It Has Been 40 Seconds GETSBOOK")) self.timer.start() spider.logger.info("定时暂停器已启动") def spider_closed(self, spider): # 爬虫关闭时终止定时器,避免资源泄漏 if self.timer: self.timer.cancel() spider.logger.info("定时暂停器已停止")
代码说明
- 定时器逻辑:保留原有
RepeatTimer实现,实现周期性触发暂停逻辑。 - 引擎控制:通过
crawler.engine.pause()/resume()实现官方标准的爬虫暂停/恢复,确保状态安全。 - 按键处理:将按键等待逻辑放入独立线程,避免阻塞Scrapy主线程;通过终端原始模式实现"任意按键"触发,无需回车确认。
- 生命周期绑定:通过
spider_opened/spider_closed信号绑定定时器的启动与销毁,保证资源合理释放。
启用中间件
在项目的settings.py中配置启用该中间件:
DOWNLOADER_MIDDLEWARES = { '你的项目名.middlewares.PauseOnTimerMiddleware': 543, }
内容的提问来源于stack exchange,提问作者Adarsh
相关产品推荐
相关产品推荐

