限流发生时,第一动作不是重试,而是把已经拿到的结果从易失的内存或临时响应里搬进一个可续跑的本地存档,同时记录每个词条的状态是“完整”“部分”还是“未开始”。保护已有结果的核心是让数据与任务进度分离:数据先落盘,进度再标记,恢复时只补缺口,不重跑全量。
限流报错通常只说明某次请求被拒,并不等于之前的结果失效。要做的是区分两种损失:一种是响应体没拿到,词条从未写入;另一种是响应体拿到了,但脚本在写文件前就中断。前者只需重试,后者需要先检查临时文件是否完整。
一个可核对的证据是看本地存档的写入时间戳与脚本日志的最后成功请求时间。如果存档时间早于日志最后成功时间,说明有结果停留在内存里没落盘,此时继续重试只会覆盖或丢失这部分数据。假设某次运行抓取了 500 个词条,日志显示第 380 条成功后开始报错,而存档文件只写到第 350 条,那 30 条就是需要优先抢救的部分,而不是从第 1 条重来。
保护已有结果的实质是让存档具备“断点信息”。每写入一条结果,同时写入三个字段:词条标识、结果内容、抓取状态。状态用固定枚举值,例如 done、partial、pending。这样恢复时脚本能直接筛选出 pending 和 partial 的词条,跳过已完成的。
动作与结果的关系很直接:改成追加写入后,即使脚本在限流时被强制中断,已完成的记录也不会被下一次启动清空,恢复时只需读取存档并计算缺口。如果仍用覆盖式写入,一次中断就可能让整批结果归零。
限流往往和请求节奏有关,但不要在没有证据时断言是频率过高。先看限流响应的类型:如果是明确的配额耗尽,等待或换时段即可;如果是短时间内连续拒绝,降低并发或增加间隔更合理。两种情况的处理不同,混用会浪费时间。
pending 与 partial 的词条。这样做的结果是:已有结果始终有一份完整副本,缺口范围清晰可数,下一步无论是等待后重跑还是换工具补数,都不影响已获得的部分。
如果这批结果只用于一次性的粗略观察,且词条数量很少,可以只保留最终汇总文件,不必维护逐条状态。但只要结果要用于后续比较、交付或多次复用,逐条状态就是必要的。判断依据是:这份数据之后是否需要知道“哪条没拿到”。需要,就必须保留缺口标记;不需要,才可以只存汇总。
另外,限流期间不要用“请求量归零”来证明脚本已经停止或被正确拦截,归零也可能只是脚本提前退出、网络中断或任务已跑完。要结合日志的最后一条记录和存档条数一起看,才能判断真实状态。
保护已有结果不只是保住数据,还要保住“为什么中断、中断在哪”的信息。建议在存档目录下留一个简短的运行记录,写明本次使用的请求间隔、被拒的大致时段、已完成条数和缺口条数。下一次运行时先读这份记录,再决定是继续补缺口还是调整节奏。这样即使换人接手,也能从存档和记录直接恢复,而不必重新猜测上次跑到哪里。