跳至内容
免费开始
返回博客

自动化网页抓取:创建可恢复的任务

Andrei Ogiolan最后更新于 1 min read
自动化网页抓取:创建可恢复的任务

开始提取

免费试用 WebScrapingAPI

领取 1,000 个免费 API 积分。无需信用卡。

开始使用
简而言之:自动化网页抓取不仅需要为脚本设置定时器。应将调度、采集、验证和交付分开处理;为每次运行分配唯一标识;并设计重试机制,以防止故障导致记录被无声复制或覆盖范围丢失。应衡量可用数据和数据时效性,而不仅仅是成功请求的数量。

一个按计划运行的采集器虽然没有抛出异常就完成了任务,但其导出的数据却包含的是昨天的数据,且产品数量仅为预期的一半。脚本确实运行了,但数据任务却失败了。在添加更多数据源或提高并发度之前,这一区别应当成为系统设计的基础。

自动化网页抓取是指通过定义好的、无人值守的工作流,对网站数据进行反复采集和转换。生产任务还需具备识别不完整结果、恢复中断工作以及说明交付内容的能力。否则,自动化只会让同样的不确定性按计划周期性地重演。

对于开发人员而言,最有用的起点是“运行契约”:范围涵盖哪些数据源、什么算作有效观测、结果存储位置,以及哪些故障应停止交付。相比于仅以退出代码作为成功信号的大型爬虫,具有这些边界条件的采集器更易于操作。

本指南以周期性目录收集为例,详细阐述了该架构。这些模式同样适用于公共目录、职位列表以及变更监控数据集。重点在于调度与恢复机制,而非承诺任何网站都能被自动抓取,也并非意味着自动化能完全取代人工审核。

定义自动化网页抓取的运行契约

首先明确最终用户将消费的输出结果。以商品目录任务为例,它可能针对每个源产品和地区提供一条观察记录,其中包含观察到的价格、货币、库存状态、源 URL 以及采集时间。在选择调度程序或决定启动多少个工作进程之前,请先编写该定义。

将必填字段与有用的可选字段区分开来。缺少产品标识符可能会导致记录无法使用;而缺少辅助图片则可能不会。明确定义对每次故障的响应方式。如果不作此区分,一位开发人员可能会删除该行数据,而另一位则会用空字符串填充,导致数据集在不同版本之间含义发生变化。

使用运行记录来描述任务,使其独立于单个行。以下是一个示例模式,并非特定平台要求的输出格式:

{
  "run_id": "catalog-eu-2026-09-10-01",
  "source_set_version": "catalog-sources-v3",
  "parser_version": "catalog-parser-v7",
  "scheduled_for": "2026-09-10T06:00:00Z",
  "started_at": "2026-09-10T06:02:00Z",
  "status": "collecting",
  "counts": {
    "requested": 0,
    "fetched": 0,
    "valid": 0,
    "rejected": 0,
    "delivered": 0
  }
}

计划时间与实际开始时间是分开的,因为延迟的任务与准时观测并不相同。记录中还应包含实际观测时间。如果将计划时间戳分配给每一行,则会暗示数据源是在实际观测之前就被观测到的。

对数据源集进行版本控制。即使解析器保持不变,添加零售商或移除表现不佳的品类也会改变数据覆盖范围。下游分析师应能够区分市场样本规模的扩大与市场本身的变化。

最后,指定负责人并制定验收政策。需决定是否允许在标记“不完整”的情况下交付部分运行结果,还是必须等待恢复后才能交付。这两种政策均无绝对的对错之分。关键在于,消费者必须能够明确您采用了哪种政策。

将定时器、爬虫和交付处理器分离

定时器决定任务的截止时间。爬虫决定请求哪些页面以及如何提取字段。交付处理程序将已通过验证的记录移至目标位置。保持这些职责的独立性,可以防止导出失败时自动触发另一次全量爬取。

阶段

输入

输出

故障边界

计划

截止时间与源配置

运行标识

缺失或重复的触发器

发现

已批准的数据源范围

请求候选项

缺少分类或分页

收集

请求和会话上下文

响应和获取结果

超时、拒绝、意外页面

验证

提取的候选记录

已接受的行和被拒绝的证据

模式或语义不匹配

交付

已接受的批次和交付标识

目标确认

部分写入或重复重放

这种划分在初期并不需要单独的服务。同一应用程序内的函数可以具有相同的显式输入和输出。先从一个可在本地测试的结构开始,然后仅将工作负载足以支撑分布式处理的阶段进行分布式处理。

请谨慎使用“调度器”一词。爬虫的内部请求调度器并不一定就是启动每日任务的系统。前者管理单次运行中的待处理请求;后者则控制新运行的开始时间。若将这两者混淆,可能会导致队列在您本意进行新的每日观察时,却恢复了昨天的爬取任务。

若使用托管的工作流运行器,请确认其时间保证。GitHub 的“scheduled-workflow”文档指出,在高负载情况下,定时事件可能会延迟,部分排队任务可能会被丢弃。因此,便捷的定时触发机制并不能保证观测时间完全精确。

设计重叠策略:跳过、排队,或允许以不同身份并行运行。切勿让两个执行进程意外地更新同一个检查点目录。对于处理时间超过预期间隔的数据源,在盲目添加重叠任务之前,应缩小范围或调整数据新鲜度要求。

对于数据采集框架本身,Scrapy 指南提供了一个有用的实现起点。无论使用哪个框架执行,您的运行契约都应保持清晰。

有限检索、分页和重试

每个自动化的网络爬取任务都需要一个明确的终止规则。请定义允许访问的主机、路径模式、适用的最大遍历深度、分页终止条件、请求超时以及运行截止时间。一个追踪所有可用链接的爬虫,即使未遇到技术错误,也可能偏离预期的数据集范围。

请根据所需字段选择检索方法。服务器渲染的内容可能仅需一个 HTTP 客户端;脚本渲染的字段则可能需要通过浏览器执行。如果文档化的源 API 其条款和数据覆盖范围符合需求,它可能提供更稳定的解决方案。我们的 Python HTTP 客户端对比指南可帮助您在引入浏览器基础设施之前评估轻量级方案。

在重试之前先对错误进行分类。临时网络故障与凭证无效或解析器不再匹配页面是不同的。如果使用同一个循环对这三种情况都进行重试,不仅会浪费资源,还会掩盖那些需要人工干预的故障。

Retry-After 标头可以以秒为单位或以 HTTP 日期形式表示等待时间。在适用情况下,请遵守服务器的指示以及您自身的请求策略。设置有限的尝试次数和任务截止时间,以防止协作等待演变为无限期运行的任务。

结果

典型的后续行动

保留

临时连接故障

有限延迟重试

尝试次数和错误类别

速率限制响应

遵守延迟并减轻压力

响应状态和下一个可响应时间

身份验证被拒绝

停止相关操作并审查会话

已屏蔽的身份验证结果

预期页面缺失

在解析前对响应进行分类

最终URL和页面类型证据

解析器不匹配

隔离并调查

解析器版本与允许的测试数据

限制单个数据源的并发量,同时设置全局并发限制。不应仅因其他队列为空,就将所有可用工作者分配给一个运行缓慢的主机。Scrapy AutoThrottle 会根据延迟相关反馈调整延迟时间,但这既不是一种权限控制机制,也不能保证您选择的请求策略是合适的。

对于分页,请记录发现过程停止的原因。显式的最后一页、重复的光标、空结果以及请求失败具有不同的含义。应将重复的光标视为潜在缺陷,而不是默认将较小的数据集视为完整结果。

在数据进入目标系统前进行验证

成功检索仅证明响应已到达,但不能证明您提取的价格属于正确的产品,也不能证明响应中确实包含产品。请在解析和交付之间进行验证,并根据数据集的特点进行相应的检查。

首先关注结构:必填字段、预期类型、稳定标识符和允许的格式。然后检查含义:货币应与金额相关联,日期应有正确的解释,商品列表应与所选变体相关联,且“无货”消息不应被转换为数字零。

Scrapy 的项处理管道为处理和验证抓取项提供了有文档记录的机制。其架构原则不仅限于某个框架:验证应是一个明确的阶段,其结果应可统计和审查。

在保留规则允许的情况下,将被拒绝的记录保存在受控的审查流中。需包含原因代码和足够的源证据以便调查。默默删除失败记录虽然使交付文件看起来更整洁,却掩盖了覆盖范围的变化。即使被拒绝的值不应出现在消费者数据集中,拒绝计数也应包含在运行报告中。

某些检查会作用于整个批次。唯一产品标识符数量的突然下降可能表明分页信息缺失;标识符重复可能揭示变体处理错误;价格分布的偏移可能反映促销活动或解析器缺陷。这些信号应触发调查;它们不足以作为自动删除异常值的充分理由。

针对具有代表性的页面类型(包括失败页面)使用经过审核的测试用例。登录页面、同意提示、已下架商品和空分类目录都是有价值的测试输入。它们能教会解析器和响应分类器哪些内容不应被视为普通记录。

切勿用 AI 置信度替代数据契约。如果模型有助于提取或分类字段,请对照经过审核的示例衡量其输出结果,并保留模型或提示词的版本。有效的 JSON 仍可能包含错误的关联或猜测值。应确保将不确定的输出与直接观察到的字段区分开来。

验收检查还应在消费者边界处运行。目标系统可能会截断字符串、将标识符解释为数字,或以意料之外的方式对缺失值进行强制转换。在宣布模式稳定之前,请通过实际的导出和导入路径验证整个往返过程。

将检查点和重放设计为不同的操作

恢复始于一个问题:你是继续中断的观察运行、重新交付现有批次,还是收集新的观察结果?这些操作可能涉及相同的 URL,但不应具有相同的标识或副作用。

Scrapy 的任务持久化文档通过 JOBDIR ,并警告不要让不同任务共享同一目录。应在正常停止后恢复;突然关机可能会导致任务状态损坏。无法序列化的请求会保留在内存中,并在暂停时丢失。当前文档还要求使用相同的 Scrapy 版本进行恢复。 在依赖检查点实现全面覆盖之前,请先测试这些条件。持久化队列虽然有用,但并非适用于整个应用程序的通用事务性检查点。

请将爬取进度与交付进度区分开来。一个页面可能已被获取并解析,但其输出尚未到达目的地。反之,即使您的 worker 丢失了确认信息,目的地也可能已接受了一批数据。若在缺乏交付标识的情况下重启整个操作,可能会产生重复行。

根据数据集定义记录键。对于当前状态的同步,源产品标识符加上相关作用域即可识别待更新的实体;对于观察历史,该键还需包含观察或运行标识符。仅使用产品标识符会覆盖您本意要保留的历史记录。

对同一已接受批次的重试,请使用稳定的交付标识符。目标端或您的交付层可识别该标识符,从而避免重复应用该批次。切勿仅因某个组件具备重复过滤功能,就声称具有“精确一次”行为。该保证取决于整个写入和确认路径。

操作

是否复用观测标识?

再次获取源数据?

继续中断的收集

是,使用实际观察时间

仅处理待处理或已明确重试的工作

重试已接受输出的交付

是

否,重复使用已接受的批次

启动新的计划观测

否

是,在新的范围内

修正解析器缺陷

保留更正溯源

取决于保留的证据和政策

确保恢复决策可审计。如果恢复运行跨越了长时间的中断,应如实标注观测窗口。其记录可能不再描述一个精确的快照。适当的应对措施可能是重新运行,而不是假装恢复后的输出是在某个特定时刻收集的。

将检查点存储视为运行状态,并根据其内容采取相应的备份和访问控制措施。切勿将敏感会话存储在无限制的共享目录中。恢复机制应仅恢复该作业,而非扩大对其所用账户的访问权限。

随批处理附上清单和确认信息

导出文件本身并不证明目标方已成功接收。应单独跟踪交付情况,包括输出标识、记录数、模式版本以及确认或失败状态。这样,操作员在重试交付时,无需猜测是否需要重新收集数据。

Scrapy feed 导出文档中会说明支持的输出格式和存储配置。应根据数据消费者的需求选择格式,而非仅基于便利性。扁平化 CSV 适用于许多表格化工作流,而嵌套数据通常需要明确的扁平化策略或能保留结构的格式。

请在批次中包含一份清单。该清单应说明观察窗口、数据源覆盖范围、接受和拒绝的记录数,以及本次运行是否为部分完成。如果某个数据源出现故障,下游用户应在将数据集视为完整比较结果之前了解这一情况。

对于文件交付,请避免以最终文件名暴露尚未写入完成的文件。应使用存储系统支持的中转和完成机制,并测试其实际行为。对于 API 交付,在发送大批量数据前,请定义重试标识和部分错误处理机制。混合响应不应迫使您猜测哪些行已被接受。

将完成状态视为一种带有证据的状态转换。“已交付”应意味着目标端的必要操作已根据合同约定成功完成,而不仅仅是导出函数返回了结果。如果消费者以异步方式获取文件,请在作业状态中保留这一区别。

在政策允许的情况下,保留可重放的已接受工件。这对恢复、调试以及重处理为新的目标模式非常有价值。将保留时间限制在工作流所需范围内,并区分源证据与规范化导出数据,以便二者各自拥有适当的生命周期。

在扩展之前,请监控数据新鲜度并测试故障路径

仪表盘上最重要的问题通常是:“最新的可用数据有多新?”如果每个工作者生成的都是被拒绝的行,那么工作者数量正常也意义不大。应根据成功观察结果或符合消费者要求的交付情况来追踪数据新鲜度,而不是依据最近一次流程启动时间。

使用独立计数监控每个阶段。请求的页面、检索到的响应、被接受的行、被拒绝的行以及已确认的交付不应合并为一个成功百分比。这些计数之间的变化将指引您调查的方向。

添加“未运行”警报。从未启动的任务无法自行发出失败消息。应通过独立检查,在预期数据未在允许的截止时间前到达时及时发现。将计划延迟与爬取速度缓慢及交付积压分别记录。

在扩展数据源集之前,应有针对性地测试中断、重复触发、会话过期、选择器变更、必填字段缺失以及目标端故障等情况。验证每种结果是否都有可控的响应,并留有足够的恢复信息。仅演示正常流程并不能证明系统的运行可靠性。

将解析器变更部署到测试数据集上,随后在批准的源数据范围内对一小部分受控的实际样本进行测试。不仅要比较行数,还要比较字段含义和覆盖范围。一个能提取更多行的新解析器,可能是遵循了某个非预期的建议组件。

将回滚与数据更正分开处理。回滚代码可防止产生更多错误输出,但无法修复已交付的记录。您的事件处理流程应识别受影响的运行 ID,在必要时通知消费者,并生成可追溯的更正操作,而非默默重写历史数据。

对实际限制工作流的环节进行扩展。如果验证环节拒绝了大部分行,增加检索处理程序只会产生更多审核工作。如果交付是瓶颈,增加浏览器并发性可能会加剧存储压力,而无法提高数据的新鲜度。

关键要点

  • 为每次自动化的网页抓取运行设定明确的范围、标识、验收规则和负责人。
  • 将调度、采集、验证和交付分离,以便每个环节都能独立发生故障并恢复。
  • 限制重试次数,并区分临时传输错误与身份验证或解析器缺陷。
  • 确保新观察结果、恢复的工作以及交付重试在语义上保持区分。
  • 在扩大规模之前,需监控可用数据的新鲜度并测试故障情况。

常见问题

每个采集字段的保留期是否应相同?

不。原始源证据、规范化记录、操作日志和身份验证状态各自用途不同,可能需要不同的生命周期。应根据用途和敏感程度定义保留策略,然后在每个存储位置验证删除操作。短期的日志策略不会自动删除较旧的导出数据或备份。

同一条管道能否支持多个客户数据集?

可以,前提是源数据范围、访问权限、状态和目标位置均经过刻意隔离。应使用显式的租户上下文,并在边界处进行验证。复用解析器代码与共享凭据或可变会话是不同的。需测试确保某一位客户的重试操作或配置变更不会导致另一位客户的数据被路由到错误的目标位置。

应如何估算数据采集成本?

对具有代表性的试点项目进行测算,包括失败尝试、浏览器执行、验证工作、存储和交付等环节。将相关总成本除以可用输出量,而非仅以请求的页面数为基准。将该数值视为针对特定工作负载的观察结果,而非适用于所有网站的通用成本。当源数据布局、覆盖范围或数据时效性要求发生变化时,应重新评估该数值。

结论

当任务不仅能报告已完成,还能说明发生了什么时,自动化网页抓取才变得可靠。运行标识、明确的验收检查、受限的重试以及已确认的交付,使故障可恢复,结果可解读。

请从较小的源数据集和完整的生命周期开始。中断任务、重试交付,并确认目标端不会收到意外的重复数据。验证未按计划执行时会触发警报,且包含错误页面的成功响应绝不会被视为普通数据。这些测试所建立的信心,比令人印象深刻的请求数量更有价值。

如果页面检索的运行是主要限制因素,请在保留您的验证和交付协议的同时,针对该组件评估 WebScrapingAPI 的 Scraper API。将检索移至服务端并不会消除定义覆盖范围或数据新鲜度的必要性。 目标是构建一条管道,其输出结果可供其他开发人员检查、在声明的限制范围内信赖,并能在无需盲目重跑整个流程的情况下进行恢复。

关于作者

Andrei Ogiolan, 全栈开发工程师 @ WebScrapingAPI

Andrei Ogiolan

全栈开发工程师

安德烈·奥吉奥兰(Andrei Ogiolan)是 WebScrapingAPI 的全栈开发工程师,他在产品各领域均有贡献,并协助为该平台构建可靠的工具和功能。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。