使用asyncio对游标分页API发起限频请求时遇错误求助
问题分析与修复方案
核心错误原因
报错TypeError: expect a list of futures, not coroutine是因为asyncio.wait()要求传入Future对象的可迭代集合,但你直接传了一个协程对象。此外代码还有异步逻辑、类定义、分页逻辑等多处问题,逐一修复如下:
修复步骤与代码示例
1. 替换同步HTTP库为异步库
requests是同步IO操作,会阻塞asyncio事件循环,必须改用异步HTTP库aiohttp。
2. 修正asyncio执行逻辑
直接用loop.run_until_complete()接收协程即可,不需要额外用asyncio.wait();如果一定要用asyncio.wait(),需把协程包装成列表传入:asyncio.wait([self.collect_data(urls)])。
3. 修复类定义错误
类定义不能带self参数,类内的初始化逻辑要放在__init__方法里,事件循环的启动逻辑要放在类方法或外部调用中,不能直接写在类体里。
4. 修复分页逻辑
下一页请求需要用返回的next_cursor构造新的URL,而不是重复请求原URL,否则会无限循环请求同一页面。
5. 使用异步兼容的限流器
同步版RateLimiter不兼容异步上下文,改用异步限流器aiolimiter.AioLimiter,确保限流逻辑不阻塞事件循环。
完整修复代码
import asyncio import aiohttp from aiolimiter import AioLimiter class FetchUrls: def __init__(self): self.rate_limiter = AioLimiter(max_calls=4, period=1) # 每秒最多4次请求 self.session = None async def fetch_request(self, url): async with self.rate_limiter: async with self.session.get(url) as response: data = await response.json() # 若API返回的next是游标而非完整URL,需自行拼接成新请求地址 return data['items'], data.get('next') async def collect_data(self, urls): data = [] async with aiohttp.ClientSession() as self.session: for url in urls: items, next_url = await self.fetch_request(url) data.extend(items) # 直接展开列表元素,避免嵌套结构 while next_url: items, next_url = await self.fetch_request(next_url) data.extend(items) return data if __name__ == "__main__": urls = ["https://api.example.com/initial-page"] # 替换为你的初始URL列表 fetcher = FetchUrls() loop = asyncio.get_event_loop() result = loop.run_until_complete(fetcher.collect_data(urls)) print(f"共获取到{len(result)}条数据")
额外说明
- 如果API返回的
next是游标参数而非完整URL,需要在fetch_request里拼接成新URL,比如:next_url = f"{base_url}?cursor={next_cursor}" aiolimiter需提前安装:pip install aiolimiter- 所有初始化和执行逻辑必须放在类方法内,避免直接在类体写执行代码,确保符合Python类的规范
内容的提问来源于stack exchange,提问作者Rod0n
相关产品推荐
相关产品推荐

