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

如何配置scrapy CrawlerProcess与asyncio脚本在同一事件循环运行

解决方案

错误原因说明

  • 第一次报错:asyncio.run()执行完毕后会主动关闭当前线程的事件循环,后续Scrapy初始化AsyncioSelectorReactor时,找不到可用的活跃事件循环,因此抛出There is no current event loop in thread 'MainThread'错误。
  • 第二次报错:CrawlerProcess.start()方法默认会启动Twisted框架自己的事件循环,而你已经通过asyncio.run()启动了一个事件循环,同一个线程内不能同时运行两个事件循环,因此抛出This event loop is already running错误。

解决步骤

1. 启用Asyncio Reactor配置

首先取消你settings.py中对应配置的注释,确保Asyncio Reactor生效:

TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"

2. 替换为CrawlerRunner

不要使用CrawlerProcess,改用专门用于嵌入场景的CrawlerRunner,它不会主动创建和启动新的事件循环,可以直接复用当前已有的asyncio事件循环。

3. 编写并发运行代码

如果你使用的是Scrapy 2.6及以上版本,可以直接用以下最简写法,将两个协程放到同一个事件循环中运行即可:

import asyncio
from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings
# 导入你自己的爬虫类
from your_spider_file import TestSpider

# 你的原有playwright协程
async def playwright_script():
    # 此处保留你原有的playwright脚本逻辑
    pass

async def run_scrapy():
    runner = CrawlerRunner(get_project_settings())
    # 直接await爬取任务完成
    await runner.crawl(TestSpider)

async def main():
    # 两个任务并发运行,如果需要先后执行,分别await即可
    await asyncio.gather(
        playwright_script(),
        run_scrapy()
    )

if __name__ == "__main__":
    asyncio.run(main())

如果你使用的是更低版本的Scrapy,需要手动绑定reactor到asyncio循环,使用以下写法:

import asyncio
import sys
from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings
from twisted.internet import asyncioreactor
# 导入你自己的爬虫类
from your_spider_file import TestSpider

# 提前将Twisted reactor绑定到当前asyncio事件循环
if 'twisted.internet.reactor' not in sys.modules:
    asyncioreactor.install(asyncio.get_event_loop())
from twisted.internet import reactor

# 你的原有playwright协程
async def playwright_script():
    # 此处保留你原有的playwright脚本逻辑
    pass

async def run_scrapy():
    runner = CrawlerRunner(get_project_settings())
    await runner.crawl(TestSpider)
    # 爬取完成后停止reactor
    reactor.stop()

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    # 同时启动两个任务
    loop.create_task(playwright_script())
    reactor.callWhenRunning(lambda: loop.create_task(run_scrapy()))
    # 启动reactor阻塞运行
    reactor.run()

注意事项

  • 不要在已有asyncio事件循环运行的场景下调用CrawlerProcess.start(),也不要在asyncio.run()执行完毕后再启动Scrapy,保证两个任务共享同一个事件循环。
  • 如果需要两个任务先后执行,只需要调整main函数中的await顺序即可,不需要额外修改配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 21:15:05