遇到限流时,最该先保护的不是“继续拿新数据”,而是把已经成功返回的结果落盘并标记状态。因为限流本身只说明调用频率或并发触发了对方限制,并不等于已有数据失效。真正危险的是程序在重试中覆盖了旧结果、把半截数据当成完整数据写库,或者因为一次失败就丢弃整批已抓到的记录。
脚本通常在一次批量任务里发很多请求。限流可能发生在第 40 条,也可能发生在第 200 条。此时程序内部可能已经持有前 39 条或前 199 条的完整响应,只是最后的异常让整个任务退出。如果脚本把“任务整体失败”直接映射成“本批无结果”,就会造成已经有价值的数据被丢弃。
另一种情况是响应已经返回,但解析阶段才出错。比如接口返回了正文,脚本在提取字段时遇到空值抛异常。若没有先把原始响应存下来,重跑时又要重新请求,反而增加再次触发限流的机会。
第一种解释是频率触发。证据是:限流前若干次调用都成功,失败集中在短时间内连续请求之后;等待一段时间再单独调用同一参数,可能恢复正常。这说明问题在调用节奏,不在数据本身。
第二种解释是结果不完整。证据是:某些请求虽然返回了状态码,但响应体缺少关键字段,或者分页信息显示还有后续页未取。这种情况下,即使不限流,已有结果也只能算部分结果,不能直接用于下一步判断。
区分这两种解释的动作很简单:把每次调用的原始响应、时间戳、请求参数和状态单独记录。然后抽取失败前后的几条记录做对比。如果失败前记录字段完整、失败后等待重试能拿到同类完整记录,偏向频率触发;如果成功返回的记录本身就缺字段或分页未闭合,偏向结果不完整。
脚本应在解析之前先把原始响应写入临时文件或本地存储,文件名包含请求标识和批次标识。写入成功后,再更新一个状态记录,例如 success、partial、rate_limited。这样即使后续解析失败,原始数据仍在。
遇到限流时,不要立即用同一批参数覆盖旧文件。更稳妥的做法是:把当前批次标记为未完成,保留已完成部分;下一次运行时只补未完成部分,而不是整批重跑。这个动作会直接影响下一步:如果旧结果被保留,你可以先基于已有完整记录做初步核对;如果旧结果被覆盖,你只能等待下一次全量请求,且再次触发限流的概率更高。
假设某脚本计划请求 100 个参数,第 61 个请求触发限流。若脚本在每次请求后立即写一条独立记录,那么前 60 条已经可用。此时可以先把这 60 条标记为“已获取”,把第 61 到 100 条标记为“待补取”。下一次运行只请求第 61 到 100 条,并在请求之间加入更长间隔。结果如何影响下一步:如果补取成功,你可以合并成完整批次;如果补取仍失败,你至少能判断是参数问题还是频率问题,而不是从零重来。
这些证据不能单独证明“处理正确”,因为请求量归零也可能只是脚本提前退出,抓取量下降也可能只是任务被跳过。要结合状态标记和原始响应一起看。具体到你所用的工具,其限流规则、重试窗口和返回结构需要以实际文档或返回信息为准,不要凭假设调整生产脚本。
把已有结果先固定下来,再区分是频率问题还是完整性问题,你才能在限流之后继续推进,而不是把已经拿到的部分也一起丢掉。