如何通过等待重试正确处理GitHub API速率限制问题
问题原因
- 你在
for循环内手动修改循环变量i的操作完全不会生效:Python的for i in range(x)执行逻辑是由迭代器按固定顺序依次给i赋值,每轮循环结束后迭代器会自动取出下一个序列值覆盖i,你在异常分支里写i = i-1只能临时改变当前轮次的i值,完全不会影响下一轮迭代的页码取值,所以才会出现i从12直接跳到13、一直不重试失败页码的情况。 - 固定5秒的等待时长不符合GitHub API的限流规则:GitHub搜索接口的限流周期是1分钟,认证用户每分钟最多发起30次搜索请求,触发限流后仅等待5秒远达不到限流重置的时间要求,会反复触发限流异常。
- 宽泛的异常捕获没有区分错误类型:你没有先判断HTTP响应状态码就直接解析JSON取
items字段,不管是限流、网络波动、接口返回格式错误都会进入异常分支,无法针对性处理限流场景。
修复方案
- 改用
while循环控制页码,只有当前页请求成功、数据全部写入结果列表后,再把页码+1,失败时不修改页码,直接重试当前页。 - 请求后先判断响应状态码,触发限流时优先读取响应头里的
X-RateLimit-Reset字段,计算距离限流重置的剩余等待时间,不用固定写死等待时长;单页设置重试次数上限,避免出现死循环。 - 不要使用无差别的裸
except,针对性捕获请求相关异常,方便排查问题。
修复后的参考代码:
import time import requests from datetime import datetime repositories = [] current_page = 1 # GitHub分页page从1开始计数 max_page = 33 max_retry = 5 # 单页最大重试次数,避免死循环 # 替换成你自己携带授权令牌的请求头 headers = { "Authorization": "Bearer YOUR_ACCESS_TOKEN", "Accept": "application/vnd.github.v3+json" } while current_page <= max_page: retry_count = 0 page_success = False while retry_count < max_retry: try: url = f"https://api.github.com/search/repositories?q=language:java&sort=forks&order=desc&per_page=30&page={current_page}" response = requests.get(url=url, headers=headers) # 优先处理限流场景 if response.status_code in [403, 429]: reset_timestamp = int(response.headers.get("X-RateLimit-Reset", time.time() + 60)) wait_seconds = reset_timestamp - int(time.time()) + 2 # 多等2秒做时间容错 print(f"触发接口限流,等待{wait_seconds}秒后重试当前页") time.sleep(max(wait_seconds, 1)) retry_count += 1 continue # 其他HTTP错误直接抛出 response.raise_for_status() resp_json = response.json() # 写入当前页数据 for repository in resp_json["items"]: dt_string = datetime.now().strftime("%d/%m/%Y %H:%M:%S") repositories.append({ "name": repository["full_name"], "link": repository["html_url"], "date": dt_string }) print(f"第{current_page}页拉取成功,当前累计获取{len(repositories)}条仓库数据") page_success = True break except Exception as e: print(f"请求第{current_page}页出错: {str(e)},10秒后重试") time.sleep(10) retry_count += 1 if page_success: current_page += 1 else: print(f"第{current_page}页重试次数耗尽,终止拉取") break print("Repositories taken.")
补充说明:
- GitHub搜索接口默认单页最多返回100条结果,你可以把请求参数里的
per_page设为100,总页数降到10页以内,能大幅降低触发限流的概率。- 你原代码从page=0开始请求,会和page=1返回重复的第一页数据,实际拉取的有效数据量会少于预期。
内容的提问来源于stack exchange,提问作者Basak Balci
相关产品推荐
相关产品推荐

