如何在aiohttp中避免「too many requests」(429)错误
解决异步请求触发429 Too Many Requests的方法
你的问题源于一次性发起120个异步请求,超出了API的速率限制。以下是几种直接可行的解决方案,基于你的现有代码修改:
1. 限制并发请求数量(最推荐)
使用asyncio.Semaphore控制同一时间发起的请求数,避免瞬间耗尽API的速率配额。
修改后的代码示例:
async def fetch_url(session, url, semaphore): async with semaphore: async with session.get(url, ssl=False) as response: return await response.json() def get_tasks(self, session, semaphore): tasks = [] for url in self.list_of_urls: tasks.append(asyncio.create_task(fetch_url(session, url, semaphore))) return tasks async def get_symbols(self): print('Parsing started') # 设定同时最多发起5个请求,可根据API限制调整数值 semaphore = asyncio.Semaphore(5) async with aiohttp.ClientSession() as session: tasks = self.get_tasks(session, semaphore) responses = await asyncio.gather(*tasks) for response in responses: print(response)
2. 添加请求间隔
如果API限制是基于时间窗口(如每分钟最多60次请求),可以在每个请求之间添加固定延迟,避免短时间内请求过载。
修改后的fetch_url函数示例:
async def fetch_url(session, url): await asyncio.sleep(0.5) # 每个请求间隔0.5秒,可按需调整 async with session.get(url, ssl=False) as response: return await response.json()
提示:该方法和并发限制结合使用,效果更佳。
3. 实现429重试机制
遇到429错误时,根据API返回的Retry-After头(若存在)等待后重试,或采用固定延迟重试。
修改后的fetch_url函数示例(带重试逻辑):
async def fetch_url(session, url, semaphore, max_retries=3): async with semaphore: for attempt in range(max_retries): async with session.get(url, ssl=False) as response: if response.status == 429: # 优先使用API指定的重试等待时间,默认等待2秒 retry_after = int(response.headers.get('Retry-After', 2)) await asyncio.sleep(retry_after) continue return await response.json() # 多次重试失败后返回错误标识 return {'error': 'Max retries exceeded'}
额外注意
- 先查阅API官方文档,明确它的速率规则(如每秒/每分钟允许的请求数),再针对性调整并发数或延迟时间。
- 逐步测试调整参数,不要盲目调高并发量。
内容的提问来源于stack exchange,提问作者Dushamishkin
相关产品推荐
相关产品推荐

