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

基于Django的异步爬虫实时数据推送方案选型与问题咨询

方案选型与SSE接入问题解决

现有方案优劣对比

  • 多进程+Pipe:爬虫能完全独立运行,不占用Django进程资源,但Pipe是点对点通信,无法直接实现多客户端的自动数据推送,用户端仍需手动刷新或额外做轮询,不符合自动更新需求,维护成本也高。
  • WebSockets:成熟的双向通信方案,但你仅需服务器单向推送数据,用WebSocket会冗余,增加不必要的复杂度,不如SSE轻量。
  • SSE:完全匹配你的单向推送场景,浏览器原生支持EventSource,客户端实现简单,服务器端开销小,确实是最优选择。你遇到的RuntimeError: asyncio.run() cannot be called from a running event loop,是因为Daphne已在运行asyncio事件循环,你重复调用asyncio.run()启动爬虫导致冲突。

SSE接入爬虫的正确姿势

解决事件循环冲突问题

不要用asyncio.run()启动异步爬虫,直接将爬虫任务加入当前运行的事件循环:

import asyncio

async def crawler_task(broadcast_queue):
    while True:
        # 采集、处理数据逻辑
        data = await fetch_and_process_data()
        # 将数据放入广播队列
        await broadcast_queue.put(data)
        # 模拟采集间隔
        await asyncio.sleep(60)

# 在SSE视图中获取当前事件循环并启动爬虫(确保只启动一次)
loop = asyncio.get_running_loop()
# 用asyncio.Queue做数据广播的中间容器
broadcast_queue = asyncio.Queue()
# 启动爬虫任务
loop.create_task(crawler_task(broadcast_queue))

实现多客户端数据推送

需要全局广播机制,让爬虫数据能推给所有订阅的SSE客户端:

  1. 维护一个客户端连接列表(或用asyncio.Queue做广播),每个SSE客户端连接时加入列表。
  2. 爬虫每次生成数据后,遍历列表给每个客户端发送SSE格式的消息。

如果你的爬虫是同步while True循环,不能直接放入异步事件循环(会阻塞),可将同步爬虫放到独立线程运行,线程将数据写入线程安全队列,SSE视图从队列读取数据推给客户端:

import threading
import queue
import time

def sync_crawler(broadcast_queue):
    while True:
        # 同步采集、处理数据
        data = sync_fetch_and_process()
        broadcast_queue.put(data)
        # 采集间隔
        time.sleep(60)

# 线程安全队列
broadcast_queue = queue.Queue()
# 启动爬虫线程
threading.Thread(target=sync_crawler, args=(broadcast_queue,), daemon=True).start()

遗漏的可选方案

Celery+消息中间件(Redis/RabbitMQ):

  • 将持续运行的爬虫作为Celery常驻任务,爬虫生成数据后发送到Redis Pub/Sub频道或RabbitMQ队列。
  • Django的SSE视图订阅对应频道/队列,收到数据后立即推给客户端。
  • 该方案解耦性更强,爬虫、Django服务、消息中间件可独立部署,扩展性更好,适合后期用户量增长的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 16:57:34