保护已有结果的核心不是继续硬跑,而是把“已拿到的数据”和“还没拿到的数据”分开处理:先落盘、再标记缺口、最后决定是缩小请求范围、改写调用节奏,还是直接退出本轮。限流本身只说明单位时间内的请求被拒绝,不等于数据错误,也不等于账号或接口永久失效;但如果不先固化结果,重试很容易覆盖或丢失已经成功的部分。
脚本调用工具时,限流可能出现在三个位置:本地并发控制、工具侧的调用频率限制、以及网络出口或代理层。三者表现相似,但处理方式不同。本地并发过高时,降低并发数通常就能恢复;工具侧限流则往往需要等待窗口重置或调整调用间隔;出口层被限制时,换并发策略无效,必须更换出口或暂停。
判断依据可以看三点:一是失败是否集中在某一时间段;二是同一批参数降低并发后是否成功;三是错误信息是否指向频率、配额或网络。只有先分清层级,才能避免把“出口被封”误当成“参数写错”而反复重跑。
只要本轮已经拿到部分成功结果,就应该先写入独立文件或数据表,并记录每条结果对应的请求参数、时间、状态。缺口不要和成功结果混在一起,否则后续重试时无法判断哪些需要补、哪些不能重复写。
一个假设例子:某脚本计划抓取1000个词,跑到第300个时开始限流。此时把前300条写入result_done.json,把剩余700条写入pending.json,并记录失败原因。下一步只针对pending.json重试,而不是从头再跑。这样做的结果是:已成功部分不会被覆盖,重试范围可控,也更容易估算剩余时间。
如果确认是频率限制,且已有结果本身可用,那么改写调用方式比重新设计查询更划算。常见动作包括降低并发、增加请求间隔、把大批量拆成小批次、在批次之间加入等待。改写的前提是:查询目标和参数不变,只是把“同时打”改成“分批打”。
需要警惕的是,降低并发后如果仍然限流,说明瓶颈可能不在本地并发,而在配额或出口层。这时继续调低并发收益有限,应考虑退出本轮,等窗口重置后再试。
退出不是失败,而是一种保护。适用前提包括:剩余请求占比很小但重试多次仍失败;限流伴随明显的配额耗尽信号;或者继续重试会触发更长时间的封禁。退出前要做的是保存现场:记录已成功数量、失败数量、最后一次成功的时间点、当前使用的参数和出口信息。这些信息决定下一轮从哪里开始,而不是凭记忆重来。
脚本里可以加一个检查点机制:每成功N条就写一次文件,并记录当前处理到的位置。限流发生后,脚本读取检查点,只处理未完成部分。这个动作的直接结果是:即使进程被中断,也不会丢失已成功的数据;同时,重试范围由检查点决定,而不是由“感觉跑了多少”决定。
如果检查点文件里同时记录了失败原因,下一步就能区分“需要换参数重试”和“需要等窗口重置”。例如,失败原因是频率限制,就先等待;失败原因是参数错误,就先修正参数,而不是盲目等待。
个别样本成功不代表规模化后仍然成立。小批量测试时没有触发限流,可能是因为请求量没达到阈值,也可能是因为时间窗口内恰好没有其他调用。把测试结果直接放大到全量,容易在规模化阶段集中失败。
另外,不同工具、不同接口、不同账号的限流规则并不一致。具体阈值、窗口长度、配额计算方式需要以实际调用反馈和官方说明为准,不能把某一次经验当成通用规则。已有结果能否继续使用,也取决于查询目标是否发生变化;如果目标参数已经调整,旧结果只能作为参考,不能直接混入新结果。
最后,请求量归零或抓取量下降,不能单独证明限流已经解除。它也可能是脚本提前退出、网络中断或参数过滤导致。判断是否恢复,应结合一次小批量试探调用的返回状态,而不是只看数量变化。