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

如何使用FastAPI集成Scrapy创建API并解决运行异常问题

FastAPI对接Scrapy搜索爬虫故障修复方案

访问异常修复

先解决服务能启动但无法访问的问题,两个基础配置错误:

  • 点击终端输出的地址打开文件资源管理器:是Windows终端的协议关联bug,和服务本身无关,不要点击终端里的链接即可。
  • 手动输入地址超时:你输错了IP,服务监听的是127.0.0.1,你输入的127.0.0.0是保留网段地址,不是本机回环地址,正确访问地址是http://127.0.0.1:8000,输对后即可正常访问。

Scrapy对接报错核心修复

你之前把独立启动的CrawlerProcess放到if __name__ == "__main__":块的调整是正确的,剩下的报错基本都是事件循环冲突、传参方式错误导致的,按下面步骤修改:

不要直接在接口函数里用CrawlerProcess跑爬虫

Scrapy依赖的Twisted reactor和uvicorn的异步事件循环默认冲突,每次请求都新建CrawlerProcess会直接触发ReactorNotRestartable报错,推荐用CrawlerRunner做对接,在FastAPI启动时一次性初始化reactor,避免重复启动:

from fastapi import FastAPI
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging
from twisted.internet import reactor
import threading
# 替换成你自己的爬虫类导入路径
from your_spider_file import SearchSpider

app = FastAPI()
configure_logging()
# 全局只初始化一次runner
runner = CrawlerRunner()

# 后台线程启动Twisted reactor,不阻塞uvicorn服务
def start_reactor():
    reactor.run(installSignalHandlers=False)
threading.Thread(target=start_reactor, daemon=True).start()

# 临时存储爬取结果,生产环境替换成Redis或数据库
result_cache = {}

@app.get("/search")
def get_search_result(keyword: str):
    # 把关键词、结果缓存对象作为参数传给爬虫
    crawl_task = runner.crawl(SearchSpider, keyword=keyword, cache=result_cache)
    # 爬取完成后返回结果
    crawl_task.addCallback(lambda _: {"keyword": keyword, "data": result_cache.pop(keyword, [])})
    return crawl_task.result

爬虫端正确接收传参

不要修改start_requests的默认方法签名,通过爬虫类的__init__方法接收外部传入的参数:

import scrapy

class SearchSpider(scrapy.Spider):
    name = "search_spider"

    def __init__(self, keyword=None, cache=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.keyword = keyword
        self.cache = cache
        # 替换成你实际要爬的搜索引擎地址
        self.start_urls = [f"https://your-target-search-site.com/search?q={keyword}"]

    def parse(self, response):
        parse_result = []
        # 替换成你自己的结果解析逻辑
        for item in response.css("div.search-result-item"):
            parse_result.append({
                "title": item.css("h3.title::text").get(),
                "link": item.css("a::attr(href)").get(),
                "abstract": item.css("div.abstract::text").get()
            })
        # 把解析完的结果存入缓存
        if self.keyword and self.cache is not None:
            self.cache[self.keyword] = parse_result
        yield from parse_result

常见报错排查

  • 报ReactorNotRestartable:检查是不是在接口请求逻辑里重复初始化了CrawlerRunner/CrawlerProcess,或者重复调用了reactor.run(),必须保证reactor只在服务启动时启动一次
  • 爬虫收不到关键词参数:检查runner.crawl()传参时是不是把参数作为关键字参数传入,爬虫类的__init__方法有没有正确接收参数并赋值给实例属性
  • 接口返回空结果:检查是不是没等爬取任务完成就直接读取缓存返回,必须等crawl的deferred任务执行完再读结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 23:42:19