遇到限流时,先不要重试,也不要立刻改脚本参数。第一步是把已经拿到的结果落盘并标记状态,再判断限流是“总量触发”还是“并发触发”。两种情况的处理路径不同:总量触发适合降低请求频率并保留断点续跑;并发触发适合把并发压到单线程并缩短单次任务窗口。判断依据是限流出现的位置——如果每次都在跑了几百条之后才出现,更可能是总量或时间窗限制;如果一开始并发就失败、单条手动执行却正常,更可能是并发限制。
限流发生时,内存里的中间结果最容易被后续重试覆盖。实际动作是:每次请求返回后立即追加写入本地文件,字段至少包含输入词、返回状态、原始响应、抓取时间。写入完成后再更新进度指针。这样做的结果是,即使脚本随后崩溃或被限流中断,下一次启动可以从指针位置继续,而不是从头再跑。
标记状态要区分三种:成功、明确失败、未知。未知指请求发出但没有拿到完整响应,例如超时或连接中断。未知条目不能当成成功直接跳过,也不能无条件重试,应当单独放一个待复核队列。这一步的影响是:后续判断限流范围时,你能知道失败是集中在某一批输入,还是均匀分布。
假设一个批量任务共一千条输入,前六百条正常,之后连续失败。这更接近总量或时间窗触发。此时合理动作是把批次拆小,每批之间加入等待,并保留断点文件。另一种假设是脚本一启动就大量失败,但把并发降到一,同样的输入又能返回。这更接近并发触发,合理动作是限制同时发出的请求数,而不是延长总时长。
选择依据可以落到一个可观察证据上:把同一批输入分别用原并发和单并发各跑一小段,比较失败出现的时机。如果单并发下失败消失,说明瓶颈在并发;如果单并发下仍在相同条数附近失败,说明瓶颈在总量或时间窗。这里要说明适用条件:这个对照只对同一时段、同一网络环境成立,跨时段比较会把时段性限制误判成并发问题。
断点续跑的关键不是记住“跑到第几条”,而是记住每条输入的状态。只记序号时,一旦中间有条目失败被跳过,后续序号会整体偏移,导致重复请求或漏请求。实际动作是给每条输入生成稳定标识,例如输入词本身或它的哈希值,用标识查状态文件决定是否跳过。
结果如何影响下一步:如果状态文件里成功条目占比高、失败集中在少数标识上,下一步应只重跑这些标识,而不是整批重来。如果失败分散且比例高,说明当前限流范围覆盖整批,应暂停并等待下一个时间窗,而不是继续消耗。
小样本下成立的做法,规模化后常出现例外。单线程顺序请求在小批量时几乎不会触发限制,但输入量上来后,即使并发为一,累计请求数仍可能触碰总量限制。此时继续压低并发没有帮助,需要的是分批和间隔。
另一个容易失效的是“失败即重试”。在限流场景下,立即重试往往加重触发条件,让原本只影响一小段的限制扩散到整批。更稳妥的是对失败条目做退避等待,并设置重试上限;超过上限的条目进入待复核队列,由人工或下一轮任务处理。
还要注意:请求量归零或抓取量下降,不能单独证明你的处理正确。它也可能是任务已完成、输入被去重、或上游返回结构变化导致的。判断处理是否有效,应结合成功条目占比和失败分布一起看,而不是只看请求数。
按这个顺序执行,限流只会中断当前批次,不会让已经拿到的结果作废;下一步该压并发还是该拆批,也能从对照结果里得到依据,而不是靠猜测调整参数。