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

Concurrent.futures结合Requests HTML调用render()报线程无事件循环问题问询

问题成因
  • requests-html的render()方法底层依赖pyppeteer执行浏览器渲染,而pyppeteer是基于asyncio异步框架实现的
  • asyncio的事件循环默认和线程绑定:只有主线程会默认创建事件循环,ThreadPoolExecutor启动的子线程没有默认的事件循环
  • 你在子线程执行的load_page_and_extract_items里调用render()时,内部执行asyncio.get_event_loop()找不到当前子线程的事件循环,就抛出了对应报错
关于把render移到as_completed循环的疑问

你把render()移到as_completed的遍历逻辑中时,代码是在主线程执行的,主线程存在默认事件循环所以不会报错,但此时所有页面的渲染操作是串行执行的,确实完全失去了并行处理的速度优势。

解决方案(两种可选,无需深入了解asyncio也能实现)

方案1:给子线程手动添加事件循环(改动最小,保留原有多线程逻辑)

只需要修改load_page_and_extract_items函数,在调用render()前给当前子线程创建并绑定事件循环即可:

import asyncio
def load_page_and_extract_items(url):
    # 给当前子线程创建并设置事件循环
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    
    response = session.get(url, headers=get_headers())
    # render javascript
    response.html.render(timeout=60, wait=3)
    source = BeautifulSoup(response.html.raw_html, 'lxml')
    
    # 用完关闭事件循环避免资源泄漏
    loop.close()

这个方案改动不到5行代码,完全不需要你理解asyncio的运行逻辑,就能保留原有多线程并行渲染的能力。

方案2:使用requests-html自带的异步API(性能更优,资源占用更低)

requests-html本身提供了AsyncHTMLSession原生支持异步并发渲染,比多线程方案更适合IO密集的页面渲染场景,实现难度也很低:

import asyncio
from requests_html import AsyncHTMLSession

async def load_page_and_extract_items(url, session):
    response = await session.get(url, headers=get_headers())
    await response.html.render(timeout=60, wait=3)
    source = BeautifulSoup(response.html.raw_html, 'lxml')
    # 这里补充你原有提取数据的逻辑

async def get_pages(remaining_urls):
    session = AsyncHTMLSession()
    tasks = [load_page_and_extract_items(url, session) for url in remaining_urls]
    # 批量并发执行所有页面的加载和渲染
    await asyncio.gather(*tasks)
    await session.close()

def main():
    asyncio.run(get_pages(urls))

这个方案不需要依赖ThreadPoolExecutor,异步本身就能实现高并发,而且共用同一个浏览器实例打开多个页签渲染,比多线程每个线程单独开浏览器的资源占用低很多。

内容的提问来源于stack exchange,提问作者José Guedes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:57:03