Scrapy CrawlProcess报reactor已安装错误原因咨询(Scrapy2.6.1)
问题原因分析(Scrapy 2.6.1 + Docker多进程场景)
出现error: reactor already installed的核心原因是你的并行工作进程创建方式(大概率是基于fork的进程复制)导致子进程继承了父进程中已初始化的reactor实例,具体细节:
- Scrapy的
CrawlerProcess在初始化阶段会自动尝试安装Twisted reactor,但如果父进程在创建子进程前,已经通过导入Scrapy模块(比如scrapy.crawler、scrapy.settings)或其他操作间接初始化了reactor,fork出来的子进程会完整复制父进程的内存空间,包括已安装的reactor状态 - 你误以为每个子进程是完全独立的全新环境,但fork模式下子进程会继承父进程的所有运行时状态,包括Twisted的reactor实例,此时子进程再调用
process.start()就会触发重复安装reactor的错误
不使用CrawlRunner的解决方向
延迟Scrapy模块的导入到子进程内部:
不要在父进程代码中提前导入Scrapy相关模块,把Scrapy的导入、CrawlerProcess的初始化都放在子进程的执行逻辑里,示例:def child_worker(): # 子进程内部才导入Scrapy模块 from scrapy.crawler import CrawlerProcess process = CrawlerProcess(settings) stats = process.crawl(**kwargs, stats_callback=lambda stats: stats) process.start() # 父进程只负责创建子进程,不碰Scrapy相关代码 if __name__ == '__main__': from multiprocessing import Process for _ in range(N): p = Process(target=child_worker) p.start()改用spawn模式创建子进程:
如果使用Python的multiprocessing,将进程启动方式设置为spawn(而不是默认的fork),spawn会启动全新的Python解释器,不会继承父进程的reactor状态,示例:import multiprocessing multiprocessing.set_start_method('spawn') def foo(): process = CrawlerProcess(settings) stats = process.crawl(**kwargs, stats_callback=lambda stats: stats) process.start() # 后续创建子进程的逻辑确保父进程完全不触发reactor初始化:
检查父进程代码,避免任何可能间接初始化reactor的操作,比如不要在父进程中调用Scrapy的配置加载、工具函数等,所有与Scrapy相关的逻辑都只在子进程中执行
内容的提问来源于stack exchange,提问作者bcsta
相关产品推荐
相关产品推荐

