关于在if/else循环中使用time.sleep控制API请求速率的技术咨询
解决API限流问题:在嵌套循环中控制请求频率
嘿,针对你遇到的这个API限流问题(每分钟最多6次请求),我来分享几个实用的解决方案,帮你在嵌套循环里优雅地控制请求节奏。
首先,咱们得明确核心需求:在遍历经纬度和年份的两层循环中,确保每分钟发送的请求数不超过6次,避免触发API的限流机制。下面两种方案各有优劣,你可以根据自己的场景选择:
方案1:简单计数式限流(适合请求耗时较短的场景)
这种方式通过计数来控制,每发送6次请求就暂停一分钟,逻辑简单直观,容易实现。
import time # 假设你的经纬度和年份列表 lats = [31.23, 40.71, 34.05] lons = [121.47, -74.00, -118.24] years = [2019, 2020, 2021, 2022, 2023] request_count = 0 max_requests_per_minute = 6 wait_after_limit = 60 # 达到上限后等待60秒 for lat, lon in zip(lats, lons): for year in years: # 构造请求参数 args = { 'interpolate': False, 'lat': lat, 'lon': lon, 'year': year # 补充你的其他参数 } # 这里替换成你的API请求代码 # response = requests.get("你的API地址", params=args) print(f"发送请求:纬度{lat},经度{lon},年份{year}") request_count += 1 # 检查是否达到限流阈值,注意最后一次请求不需要等待 is_last_request = (lat == lats[-1]) and (year == years[-1]) if request_count % max_requests_per_minute == 0 and not is_last_request: print(f"已发送{request_count}次请求,触发限流,等待60秒...") time.sleep(wait_after_limit)
优点:代码简洁,容易理解和维护。
缺点:如果单个请求耗时较长(比如超过10秒),可能会导致一分钟内实际发送的请求数不足6次;反之,如果请求极快,可能会在短时间内发完6次,剩下的时间空闲。
方案2:时间窗口式限流(更精确,适配请求耗时波动的场景)
这种方式会记录每次请求的时间戳,确保在任意60秒的窗口内,请求数不超过6次,能更精准地贴合API的限流规则。
import time from collections import deque lats = [31.23, 40.71, 34.05] lons = [121.47, -74.00, -118.24] years = [2019, 2020, 2021, 2022, 2023] max_requests_per_minute = 6 time_window = 60 # 时间窗口为60秒 # 用双端队列存储最近6次请求的时间戳,自动淘汰超出窗口的记录 request_timestamps = deque(maxlen=max_requests_per_minute) for lat, lon in zip(lats, lons): for year in years: args = { 'interpolate': False, 'lat': lat, 'lon': lon, 'year': year # 补充你的其他参数 } now = time.time() # 移除时间窗口外的旧请求记录 while request_timestamps and now - request_timestamps[0] > time_window: request_timestamps.popleft() # 如果窗口内已经有6次请求,计算需要等待的时间 if len(request_timestamps) >= max_requests_per_minute: wait_seconds = time_window - (now - request_timestamps[0]) print(f"请求达到限流阈值,等待{wait_seconds:.1f}秒...") time.sleep(wait_seconds) # 等待后更新当前时间 now = time.time() # 发送API请求 # response = requests.get("你的API地址", params=args) print(f"发送请求:纬度{lat},经度{lon},年份{year}") # 记录当前请求的时间戳 request_timestamps.append(now)
优点:精准控制请求频率,不管单个请求耗时多久,都不会违反每分钟6次的限制。
缺点:代码比计数式稍复杂,但逻辑清晰,稳定性更强。
额外建议:处理API限流错误(429状态码)
即使做了限流控制,有时候还是可能因为网络延迟、API侧的统计误差等原因收到429(请求过多)的响应。这时候可以添加重试机制,配合指数退避策略:
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 创建带重试策略的会话 session = requests.Session() # 设置重试规则:最多重试3次,遇到429错误时自动重试,每次等待时间指数增长 retry_strategy = Retry( total=3, backoff_factor=1, # 等待时间:1s → 2s → 4s status_forcelist=[429], ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) session.mount("http://", adapter) # 之后用session.get/post发送请求,会自动处理429重试 # response = session.get("你的API地址", params=args)
最后提醒一下,最好再仔细核对一下API的官方文档,确认限流规则是严格的“每分钟6次”,还是滚动窗口限制,或者有没有额外的每日请求上限,这样能让你的限流逻辑更贴合实际要求。
内容的提问来源于stack exchange,提问作者Pyrmon55
相关产品推荐
相关产品推荐

