如何在多线程环境下使用requests-html渲染异步页面?
解决requests-html异步场景下arender()不生效的问题
嘿,我看到你遇到了一个头疼的问题:用AsyncHTMLSession的arender()渲染动态页面,但返回的HTML还是初始的空表格,根本没加载JS生成的内容。问题出在你把异步会话和线程池混用了,这直接打乱了requests-html的JS渲染机制。
为啥会这样?
AsyncHTMLSession本身就是为asyncio异步场景设计的,它的arender()方法依赖asyncio的事件循环来启动无头浏览器执行JS。但你用loop.run_in_executor()把异步的fetch函数丢进了线程池,相当于把异步代码放到了独立线程里跑,这会导致arender()无法正确绑定主事件循环,JS渲染过程压根没触发,自然拿不到渲染后的内容。
修复后的正确代码
我们只需要去掉多余的ThreadPoolExecutor,用AsyncHTMLSession原生的异步方式来处理请求就好:
from pprint import pprint import asyncio from requests_html import AsyncHTMLSession async def fetch(session, url): r = await session.get(url) # 给渲染加个超时时间,确保JS有足够时间加载表格内容 await r.html.arender(timeout=20) return r.html.html # 返回渲染后的完整HTML文本 def parseWebpage(page): # 这里可以换成你实际的解析逻辑,比如提取表格数据 if '<table' in page: print("✅ 成功获取到渲染后的表格内容!") # 打印前1000个字符看看效果 pprint(page[:1000]) async def get_data_asynchronous(): urls = [ 'http://www.fpb.pt/fpb2014/!site.go?s=1&show=jog&id=258215' ] async with AsyncHTMLSession() as session: # 直接创建异步任务列表 tasks = [fetch(session, url) for url in urls] # 并发执行所有任务并收集结果 responses = await asyncio.gather(*tasks) for response in responses: parseWebpage(response) def main(): # 用asyncio.run()简化事件循环管理(Python 3.7+支持) asyncio.run(get_data_asynchronous()) if __name__ == "__main__": main()
一些额外的小建议
- 如果要爬多个URL,直接往
urls列表里加就行,asyncio.gather()会自动帮你并发处理 - 可以给
arender()加浏览器参数来优化性能,比如禁用图片加载:await r.html.arender(timeout=20, options={'args': ['--no-sandbox', '--disable-images']}) - 如果遇到渲染超时,适当调大
timeout参数,确保JS有足够时间加载动态内容
内容的提问来源于stack exchange,提问作者Joao Pereira
相关产品推荐
相关产品推荐

