使用aiohttp调用Rule34 API时无法转换请求结果为文本
使用aiohttp调用Rule34 API时大请求冻结的问题
我尝试用aiohttp调用Rule34 API,当调用text()或json()方法时程序直接冻结:
import aiohttp import asyncio async def foo(): async with aiohttp.ClientSession() as session: r = await session.get('https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=1000') print('got response') # 这行能正常输出 text = await r.text() # 程序在这里冻结 print(text) # 永远到不了这里 asyncio.run(foo())
但把URL里的limit=1时程序能正常运行,而且用requests库不管limit设多大都没问题:
import requests r = requests.get('https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=1000') print(r.text)
调试后发现,调用await r.text()前r._body是None,数据在r.content._buffer里但没完全下载,试了await r也没用,不知道原因出在哪。
问题原因与解决办法
核心问题:会话关闭过早
你在async with aiohttp.ClientSession()的缩进块外面调用r.text(),这时候会话已经被关闭了。aiohttp的响应对象依赖会话的连接来完成数据下载,会话关闭后,剩余的响应数据无法继续读取,导致程序卡在await r.text()。
requests库是同步的,调用get()时已经把整个响应数据下载完成了,所以不存在这个问题;而limit=1时数据量极小,可能在会话关闭前就已经完成了数据下载,所以不会冻结。
修复代码
把读取响应的代码放到async with ClientSession()的缩进块内,保证会话在数据读取完成前保持打开:
import aiohttp import asyncio async def foo(): async with aiohttp.ClientSession() as session: r = await session.get('https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1&limit=1000') print('got response') text = await r.text() # 现在能正常读取 print(text) asyncio.run(foo())
额外优化建议
- 直接用
await r.json()来解析JSON响应,比先转文本再解析更高效:
data = await r.json()
- 可以设置超时时间,避免长时间无响应:
r = await session.get(url, timeout=aiohttp.ClientTimeout(total=30))
内容的提问来源于stack exchange,提问作者Ogurchik
相关产品推荐
相关产品推荐

