先给结论:限流发生后,不要立刻重试整批任务,而应先把已经拿到的结果落盘并冻结,再判断限流是配额型还是并发型,最后只补跑缺口。这样做的原因是,多数脚本在收到限流响应后仍会把未完成项写成空值或默认值,覆盖掉上一轮的有效数据,损失往往比限流本身更大。
限流响应到达时,脚本通常正处于批量循环的中段。此时内存里可能同时存在三类数据:已成功返回的记录、部分字段缺失的记录、以及尚未发起的请求。如果直接让循环继续或整体重跑,第三类会补上,但第二类可能被新结果覆盖成更差的状态。
实际动作是让脚本在捕获限流信号后立即停止发新请求,把当前内存中的结果按已完成、部分完成、未开始三种状态分别写入本地文件,并记录每条的抓取时间。这一步的结果决定了下一步:只有确认已成功记录没有被写坏,才有必要讨论补跑策略;如果落盘文件里已经混入空值,就要先回退到上一份快照,而不是在坏数据上继续叠加。
判断是否被覆盖,可以对比两次落盘的同一条记录:如果某条之前有值、现在为空,且时间戳更新,基本可以确认是限流期间的误写,而不是数据源本身下架。
两种限流的处理方向不同,选错会让恢复过程反复触发同一限制。
选择依据来自限流响应的形态和触发时机:如果少量请求也被拒,偏向配额问题;如果只在并发升高时被拒、降下来就好,偏向并发问题。假设某次任务共 500 条,前 200 条成功、50 条部分完成、250 条未开始,且限流在并发调到 20 后出现——按并发型处理,先降到 5 并发补跑 250 条未开始项,观察是否稳定,再决定部分完成项怎么补。这只是说明比较方法的假设例子,不代表任何具体工具的配额数值。
全量重跑会重复消耗配额,还可能把已经稳定的历史结果再次置于被覆盖的风险中。更稳妥的做法是维护一份缺口清单,字段至少包括任务标识、缺失字段、上次尝试时间、尝试次数。
补跑动作分三步:先按缺口清单生成只含未完成项的输入文件;再对部分完成项做字段级补抓,而不是整条重抓;最后把补跑结果合并回主文件时,用「新值非空才覆盖旧值」的规则写入。这样即使补跑再次被限流,已有字段也不会丢。
例外情况是数据本身有时效性:如果部分完成项抓取时间已经超过你设定的有效期,字段级补抓可能拿到与旧值不一致的结果,这时应整条重抓并同时保留旧版本,而不是简单覆盖。
限流保护的关键不在重试次数,而在退出时的状态保存。可以在脚本里约定:捕获限流信号后,先写状态文件,再决定退出或等待。状态文件至少记录本次运行的成功数、缺口数和最后一条成功记录的标识。
这样下次运行时不依赖内存,而是从状态文件恢复进度。一个可用的检查方式是:手动中断脚本后重新运行,看它是否从缺口清单继续,而不是从头开始。如果做不到,说明结果保护还停留在内存层,需要先补上落盘环节。
限流解除后,先用一条已知有效的查询验证返回结构是否与之前一致,再放开批量补跑。返回结构若发生变化,先处理解析逻辑,否则补跑结果会以另一种方式写坏已有数据。