Django使用requests_html调用render()报错无当前事件循环如何解决
问题原因
- Django服务默认采用多线程模式处理请求,即使你没有主动创建线程,每个用户请求也会由独立的工作线程处理。
- requests-html的
render()方法底层依赖异步库pyppeteer,asyncio默认只会在主线程初始化事件循环,处理请求的子线程没有默认绑定的事件循环,因此调用render()时会抛出该异常。
解决方案
方案1:手动为当前线程绑定事件 loop
在调用render()前手动创建事件循环并绑定到当前线程,处理完成后关闭循环即可,改造成本最低,兼容传统WSGI部署模式,修改后的视图代码如下:
import asyncio from django.http import HttpResponse from django.core.validators import URLValidator from requests_html import HTMLSession from bs4 import BeautifulSoup from .main import * def index(request): url = request.GET.get('url') # 原有URL校验逻辑 loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) session = HTMLSession() resp = session.get(url) resp.html.render() # 后续页面解析逻辑 loop.close() return HttpResponse("解析完成")
方案2:使用异步视图
如果你的Django版本 >=3.1,可以直接采用异步视图搭配AsyncHTMLSession实现,原生支持事件循环,不需要手动创建:
from django.http import HttpResponse from django.core.validators import URLValidator from requests_html import AsyncHTMLSession from bs4 import BeautifulSoup from .main import * async def index(request): url = request.GET.get('url') # 原有URL校验逻辑 session = AsyncHTMLSession() resp = await session.get(url) await resp.html.render() # 后续页面解析逻辑 return HttpResponse("解析完成")
注意该方案需要将项目部署在ASGI服务器(如Uvicorn、Daphne)上才能生效。
方案3:移除render()依赖
如果目标页面不需要执行JS就能获取到需要的内容,可以直接放弃render()调用,用BeautifulSoup直接解析resp.html.html的静态内容,完全避开asyncio相关的问题。
内容的提问来源于stack exchange,提问作者Javi
相关产品推荐
相关产品推荐

