使用Requests-HTML渲染网页JS时AsyncToSync与异步事件循环冲突报错
报错原因
AsyncHTMLSession 实例初始化后会在当前线程绑定一个异步事件循环,你使用 @async_to_sync 装饰器将异步函数转为同步调用的逻辑,和已存在的事件循环产生了冲突。这个报错的核心逻辑是:AsyncToSync 仅适用于完全没有运行中事件循环的同步环境,当当前线程已经存在事件循环时,不需要做同步转换,直接 await 调用异步函数即可。
你当前的代码里 search 是同步函数,直接调用被 async_to_sync 装饰的异步函数,就触发了这个冲突。如果要沿用 Requests-HTML,最简单的修复方式是要么放弃异步逻辑,直接使用同步的 HTMLSession 调用 render() 方法执行 JS,要么将整个 search 函数也改为异步实现,去掉 async_to_sync 装饰器,直接 await extract_links()。
替代方案推荐
以下都是简单易上手、性能优于 Requests-HTML 的方案:
- Playwright(Python版):微软官方维护的自动化工具,同步、异步调用模式都支持,内置浏览器内核,无需手动下载驱动,无头模式资源占用低,执行 JS、渲染动态页面的稳定性远高于 Requests-HTML,API 设计简洁,对异步开发经验不足的用户非常友好。
- DrissionPage:国产封装工具,同时整合了 HTTP 请求和浏览器渲染能力,不需要处理复杂的异步事件循环逻辑,语法贴合普通 Python 开发者的使用习惯,几乎没有学习成本,性能足够支撑中小规模的爬取需求。
- Pyppeteer:Headless Chrome 的 Python 封装,原生支持异步,性能高,API 和前端常用的 Puppeteer 对齐,适合有简单前端基础的用户使用,渲染动态页面的效果比 Requests-HTML 好很多。
- httpx + parsel:如果后续不需要大量执行 JS、仅部分接口需要异步请求,可以用 httpx 替代 requests 做 HTTP 请求,parsel 替代 HTML 解析,整套方案轻量化、性能极高,没有多余的依赖。
内容的提问来源于stack exchange,提问作者José Guedes
相关产品推荐
相关产品推荐

