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

循环运行Scrapy Spider遇ReactorNotRestartable错误及挂起问题求助

解决Scrapy循环爬取触发ReactorNotRestartable的问题

为啥会出问题

Twisted的反应器(reactor)是单例模式,只能启动一次。你原来的代码在循环里每次都新建CrawlerProcess并调用process.start(),第一次启动后反应器就没法再重启了,直接抛ReactorNotRestartable错误。换成stop_after_crawl=False后,反应器一直保持运行,但后续的爬取没通过正确的异步方式调度,程序就直接挂住不动了。

靠谱的解决办法

办法1:用同一个反应器搞定所有爬取

把爬虫类移到循环外面,每次循环给爬虫传不同的参数(比如你的i值),然后用同一个CrawlerProcess把所有爬取任务都调度好,最后只启动一次反应器就行。

改完的代码示例:

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from scrapy_splash import SplashRequest
from abc import ABC

# 爬虫类只定义一次,别放循环里
class MySpider(scrapy.Spider, ABC):
    name = "my_spider"
    start_urls = ["http://example.com"]

    def __init__(self, target_i, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.target_i = target_i  # 接收循环传过来的i值

    def start_requests(self):
        for url in self.start_urls:
            # 把你原来的dec判断换成用self.target_i的逻辑,这里先写个示例匹配
            if self.target_i == self.target_i:  # 替换成你实际的判断条件
                yield SplashRequest(url=url, callback=self.parse_data, args={"wait": 1.5})

    def parse_data(self, response):
        items = {}  # 这里要初始化items,原代码没定义
        data = response.css("td.right.data").extract()
        items["Data"] = data
        yield items

if __name__ == "__main__":
    settings = get_project_settings()
    process = CrawlerProcess(settings)

    # 循环调度爬取任务
    for i in range(0, 10):
        settings["FEED_URI"] = f"/../Data/data_{i}.json"
        # 把i传给爬虫实例
        process.crawl(MySpider, target_i=i)

    # 只启动一次反应器,所有任务会挨个执行
    process.start()

办法2:每次爬起开个新进程(简单粗暴但有效)

如果就想每次爬取都是独立的,可以用子进程来跑,这样每个子进程里的反应器都是全新的,不会有重启问题。

示例代码:

import subprocess
import sys

# 循环启动子进程执行爬取
for i in range(0, 10):
    subprocess.run([
        sys.executable, 
        __file__, 
        str(i)
    ])

# 下面是单独的爬取逻辑,只有子进程会执行这段
if __name__ == "__main__":
    import scrapy
    from scrapy.crawler import CrawlerProcess
    from scrapy.utils.project import get_project_settings
    from scrapy_splash import SplashRequest
    from abc import ABC

    class MySpider(scrapy.Spider, ABC):
        name = "my_spider"
        start_urls = ["http://example.com"]

        def __init__(self, target_i, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.target_i = target_i

        def start_requests(self):
            for url in self.start_urls:
                if self.target_i == self.target_i:  # 替换成你的实际判断逻辑
                    yield SplashRequest(url=url, callback=self.parse_data, args={"wait": 1.5})

        def parse_data(self, response):
            items = {}
            data = response.css("td.right.data").extract()
            items["Data"] = data
            yield items

    # 拿到命令行传过来的i值
    target_i = int(sys.argv[1])
    settings = get_project_settings()
    settings["FEED_URI"] = f"/../Data/data_{target_i}.json"
    
    process = CrawlerProcess(settings)
    process.crawl(MySpider, target_i=target_i)
    process.start()

顺便提几个原代码的小问题

  • 原代码里用了self.urls,但只定义了start_urls,应该改成self.start_urls。
  • items变量没初始化,得在parse_data里先创建字典或者Scrapy的Item实例。
  • dec变量没定义,记得换成你实际要判断的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:45:46