Python爬虫requests装饰器频繁报'too many calls'错误如何解决?
报错原因
- 速率限制装饰器逻辑不完整:你仅使用了
@limits装饰器限制调用次数,但没有配套处理触发的RateLimitException异常,现有代码遇到超限错误仅等待0.5秒就重试,远达不到速率重置的等待要求。 - 函数内部的额外请求未纳入计数:
@limits装饰器仅统计get_numbers函数的调用次数,但你在函数内部判断状态码非200时,额外发起了2次未被装饰器计数的requests.get请求,实际请求量远高于你设置的15次/15分钟的上限,直接触发站点的限流规则。 - 速率设置与站点规则不匹配:你订阅pro-football-reference服务后,未对齐官方给出的速率限制要求,自行设置的15次/15分钟可能本身就超过了站点允许的请求频率。
- 数据存储逻辑异常:当前仅在遇到报错时才将数据写入本地pickle文件,正常运行过程中不会落盘,若程序意外崩溃会导致已爬数据丢失,同时重复爬取已请求过的号码进一步增加无效请求量。
解决方案
- 配套重试装饰器修正限流逻辑:将
backoff重试装饰器和limits配合使用,统一管理请求和重试,避免手动发起未计数的额外请求,示例修改如下:
FIFTEEN_MINUTES = 900 # 参考官方限流值调低20%预留缓冲,可根据你订阅的服务规则调整具体数值 @on_exception(expo, RateLimitException, max_tries=5) @limits(calls=10, period=FIFTEEN_MINUTES) def get_numbers(jersey): url = f'https://www.pro-football-reference.com/players/uniform.cgi?number={jersey}' page = requests.get(url, timeout=10) time.sleep(10) if page.status_code != 200: # 非200状态码直接抛出异常,交给装饰器统一重试 raise Exception(f"请求失败,状态码:{page.status_code}") html_content = page.text soup = BeautifulSoup(html_content, "lxml") return soup
- 调整超限等待时长:删除现有代码中遇到"too many calls"仅等待0.5秒的逻辑,改为至少等待60秒再重试,或直接交给
backoff的指数退避逻辑自动处理等待时长。 - 优化数据落盘逻辑:每爬完3-5个号码就将数据写入pickle文件,不要仅在报错时落盘,减少重复请求。
- 修正球员数据存储逻辑:当前代码遍历每个号码的球员列表时,会反复覆盖
data[uni_num]的值,导致每个号码仅保留最后一个球员的信息,建议修改为每个号码对应一个列表,逐个追加球员数据:
# addplayerdata函数内修改存储逻辑 if uni_num not in data: data[uni_num] = [] for x in range(len(table_rows)): headings = [] for th in table_rows[x]: headings.append(th.text.replace('\n', ' ').strip()) player_dict = {"Player Name":headings[0],"Year From":headings[1],"Year To":headings[2],"AV":headings[3]} data[uni_num].append(player_dict)
内容的提问来源于stack exchange,提问作者Graham Waters
相关产品推荐
相关产品推荐

