限流发生后,最先要保住的不是“继续抓”,而是已经拿到的那部分结果和它的可续接性。如果脚本把每次返回都只放在内存里、失败就整批重跑,那么限流一来,之前成功的数据会随进程一起消失。可行的做法是:把结果落盘为可追加的本地文件,记录每个查询项的处理状态,限流时只暂停、不丢弃,恢复后从断点继续。下面按“你手里已经有一批跑了一半的结果”这个对象,逐步拆成可执行的处理方案。
同样是请求失败,含义不同,保护重点也不同。你需要从返回内容和本地日志里区分三类信号:
区分清楚后,动作就明确了:只有第二类才需要触发“暂停并保存”,第一类降速重试,第三类应记录为“已处理但为空”,不要反复请求同一项。
保护已有结果的核心是让每一条成功数据在写入磁盘后才算完成。可以按查询项为最小单位,维护一个状态文件与一个数据文件:
这样做的直接结果是:无论进程是被限流中断还是被手动停止,重启后都不会重复请求已完成的项,也不会因为一次失败丢掉全部进度。假设你有 200 个查询项,跑到第 80 项时被限流,落盘结构能让你从第 81 项继续,而不是从第 1 项重来——这里的数字只是说明比较方法,不代表任何实际规模。
检测到限流信号后,脚本应先完成当前这一条的写入,再进入等待,而不是立刻抛出异常退出。等待时长可以采用递增策略:首次等待较短,连续触发则延长,并设置一个上限,避免无限等待。关键在于等待期间不发起新请求,也不清空已写入的数据。
一个容易被忽略的动作是:在暂停前把“当前处理到哪一项”单独记下来。很多脚本只记录成功项,不记录中断位置,恢复时仍会从头扫描状态文件,虽然不会重复请求,但会浪费一次全量比对。记录中断位置后,恢复逻辑可以直接跳到断点,处理顺序也更可控。
恢复后不要立即用原并发量重试。先用较低并发跑少量项,观察是否再次触发限流,再决定是否逐步恢复。这个动作的结果会直接影响下一步:如果低并发稳定,说明之前是并发过高;如果低并发仍被限流,则更可能是单位时间请求总量或账号层面的限制,需要拉长间隔而不是只降并发。
暂停不等于数据可用。限流前后拿到的结果,需要确认口径一致:请求参数、时间范围、查询项定义是否在中断前后发生变化。如果中途改过参数,前后两段数据就不能直接拼接。此时应把改动点记录下来,把数据分成两段分别标注,而不是合并成一份看似完整的结果。
另外,请求量归零或抓取量骤降,不能单独证明限流已经解除,也不能证明你的处理方式正确。它还可能来自查询项本身无数据、脚本提前退出、时间范围为空等合理解释。判断是否恢复,应结合多次小批量试跑的结果,而不是只看一次统计。
处理完当前这批结果后,建议固定三件事:状态文件是否覆盖所有查询项、中断位置是否被记录、恢复逻辑是否经过一次模拟中断的验证。模拟中断可以手动在跑到一半时停止脚本,再重启,观察是否重复请求已完成项——这是验证落盘结构是否真的有效的实际动作,结果直接决定你下次遇到限流时能否放心暂停。
如果这些条件都满足,限流就只是让任务变慢,而不是让已有结果作废;如果不满足,优先补齐落盘与断点记录,再考虑调整请求节奏。具体工具的当前功能、额度和限制条件需要以你实际使用的版本为准进行核对。