AsyncHTMLSession返回响应列表无序,如何实现有序返回?
解决requests-html异步请求结果乱序问题
使用requests-html的异步模式结合BeautifulSoup做页面解析,比普通requests工具效率更高,但调用asession.run()执行异步任务时,返回的响应顺序会随请求完成时间变化,而非保持任务提交的固定顺序。不想通过URL作为键构建字典来排序,求更简洁的解决方案,要求响应能稳定保持提交时的顺序。
示例代码
from requests_html import AsyncHTMLSession, HTMLSession, HTMLResponse from bs4 import BeautifulSoup asession = AsyncHTMLSession() async def kucoin(): print(f'get K') r = await asession.get('https://kucoin.com') return r async def gateio(): print(f'get g') r = await asession.get('https://gate.io') return r async def vk(): print(f'get vk') r = await asession.get('https://vk.com') return r tasks = [kucoin, gateio, vk] results = asession.run(*tasks) for result in results: print(BeautifulSoup(result.text).title)
实际运行结果
get K get g get vk <title>Buy/Sell Bitcoin, Ethereum | Cryptocurrency Exchange | Gate.io</title> <title>Crypto Exchange | Bitcoin Exchange | Bitcoin Trading | KuCoin</title> <title>Welcome | VK</title>
更新说明
已确认requests-html返回无序响应是正常设计:AsyncHTMLSession.run()方法内部按任务完成的先后顺序返回结果,而非任务提交的顺序,这是底层异步机制优先返回先完成请求的特性导致的。
解决方案
方案1:给任务绑定索引,按索引排序
直接使用原生asyncio的方式,给每个任务添加索引标识,收集结果后按索引排序,确保顺序和任务提交一致:
import asyncio from requests_html import AsyncHTMLSession from bs4 import BeautifulSoup asession = AsyncHTMLSession() async def fetch(index, url): label = ['K', 'g', 'vk'][index] print(f'get {label}') r = await asession.get(url) return (index, r) async def main(): urls = [ 'https://kucoin.com', 'https://gate.io', 'https://vk.com' ] # 创建带索引的异步任务 tasks = [fetch(i, url) for i, url in enumerate(urls)] # 等待所有任务完成 results = await asyncio.gather(*tasks) # 按索引排序,恢复原始顺序 sorted_results = sorted(results, key=lambda x: x[0]) # 遍历输出结果 for _, result in sorted_results: print(BeautifulSoup(result.text).title) if __name__ == '__main__': asyncio.run(main())
方案2:封装任务返回标识,自定义排序逻辑
如果需要保留原有的函数结构,可以在每个任务的返回值中加入自定义标识,后续根据标识排序:
from requests_html import AsyncHTMLSession from bs4 import BeautifulSoup import asyncio asession = AsyncHTMLSession() async def kucoin(): print(f'get K') r = await asession.get('https://kucoin.com') return ('kucoin', r) async def gateio(): print(f'get g') r = await asession.get('https://gate.io') return ('gateio', r) async def vk(): print(f'get vk') r = await asession.get('https://vk.com') return ('vk', r) async def main(): # 定义原始任务顺序 task_order = ['kucoin', 'gateio', 'vk'] tasks = [kucoin(), gateio(), vk()] results = await asyncio.gather(*tasks) # 按预设顺序排序结果 sorted_results = sorted(results, key=lambda x: task_order.index(x[0])) for _, result in sorted_results: print(BeautifulSoup(result.text).title) if __name__ == '__main__': asyncio.run(main())
补充提示
如果一定要使用asession.run(),可以让每个任务返回包含标识的元组,再对asession.run()的返回结果进行排序,逻辑和上述方案一致,但直接使用原生asyncio会更灵活可控。
内容的提问来源于stack exchange,提问作者Grizzly
相关产品推荐
相关产品推荐

