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

FastAPI调用Scrapy二次请求报ReactorNotRestartable错误如何解决

错误根因
  • CrawlerProcess 内部依赖Twisted的Reactor事件循环,而Twisted的Reactor设计上仅允许被启动1次。原代码全局初始化了process实例,且每次请求都调用process.start(),第一次请求执行完成后Reactor已经处于停止状态,第二次请求尝试重启就会抛出twisted.internet.error.ReactorNotRestartable错误。
修复方案

提供两种生产环境常用的可行方案:

方案1:使用CrawlerRunner配合异步事件循环(推荐,适配FastAPI异步特性)

该方案将Twisted的Reactor与FastAPI使用的asyncio事件循环整合,全程复用同一个事件循环,无需重复启停Reactor,资源消耗更低:

import asyncio
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings
from twisted.internet import asyncioreactor

# 必须在导入其他Twisted相关模块前完成反应器注册
asyncioreactor.install(asyncio.get_event_loop())

class Request(BaseModel):
    someIDs: List[str]

# 全局初始化CrawlerRunner即可,无需使用CrawlerProcess
runner = CrawlerRunner(get_project_settings())
app = FastAPI()

@app.post("/")
async def home(request: Request):
    # 将Scrapy爬虫任务包装为异步任务等待执行完成
    deferred = runner.crawl('rt_criteria', ids=request.someIDs)
    await asyncio.wrap_future(deferred.asFuture(asyncio.get_event_loop()))
    return {"crawled": True}

# 启动命令不变:uvicorn main:app --reload

方案2:每次请求启动独立子进程运行爬虫

如果不想调整原有同步逻辑,可以把爬虫逻辑放到独立子进程中执行,子进程结束后自动销毁Reactor实例,不会影响后续请求:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
import multiprocessing
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

class Request(BaseModel):
    someIDs: List[str]

app = FastAPI()

# 爬虫逻辑封装为独立函数,仅在子进程内部执行
def run_crawler(ids: List[str]):
    process = CrawlerProcess(get_project_settings())
    process.crawl('rt_criteria', ids=ids)
    process.start()

@app.post("/")
def home(request: Request):
    # 每次请求启动独立子进程执行爬虫任务
    p = multiprocessing.Process(target=run_crawler, args=(request.someIDs,))
    p.start()
    p.join() # 等待爬虫任务执行完成后返回
    return {"crawled": True}

# 启动命令不变:uvicorn main:app --reload

该方案注意事项:不要全局初始化CrawlerProcess,必须将实例化逻辑放到子进程执行的函数内部,保证每个子进程都有独立的Reactor实例;并发请求量大的场景下子进程资源消耗会高于方案1。

内容的提问来源于stack exchange,提问作者Mohammad Reza Karimi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 00:54:03