mcpField
S
scrape-spec

scrape-spec

github.com/zytedata数据与数据库11167 次安装2 天前更新
代码仓库

关于 scrape-spec

scrape-spec 用于扩展并验证网站数据提取规范。它抽取详情页和列表页样本、比较 HTML 变体,并生成提取值与导航数据。

主要功能

  1. 01抽样详情页和列表页
  2. 02比较原始与渲染 HTML
  3. 03验证规范字段的提取值
  4. 04生成导航数据类型

适用场景

  1. 01扩展初始网站规范
  2. 02检查不同页面变体的提取结果
  3. 03从页面样本生成导航值

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/zytedata/skills --skill scrape-spec

安装后在 Claude Code 中输入/scrape-spec确认已加载。

详细介绍

你正在扩展并验证由 /scrape-define 起草的提取规范。下载不同类型的详情页和列表页,对比 HTML 变体,提取值,并可选择提交浏览器审查。

阅读 ${CLAUDE_SKILL_DIR}/../scrape/references/python-environments.md。

输入是一个规范文件夹,其中至少包含一个带有架构和 1 个页面的数据类型(来自 /scrape-define)。输出是包含更多页面、已验证值和导航数据类型的同一文件夹。

输入

原始参数字符串为 $ARGUMENTS——一个按原样使用的单一值:

  1. site_path:站点规范文件夹的路径,例如 .scrape/books-toscrape

步骤 1:读取现有规范

读取 {site_path}/spec.json,获取 url 和 data_types。

对于主要数据类型(data_types 中第一个不为 "navigation" 的类型),读取:

  • {site_path}/{data_type}/spec.json → schema、html_variant

从 site_path 派生 site_name(最后一个路径组件,例如 books-toscrape)。

步骤 2:探索站点

阶段 1 不存储页面——只存储架构和值。阶段 2 通过子 Agent 使用 /scrape-explore-site 下载少量新样本。

Agent(description="explore-site", prompt="Run /scrape-explore-site {url} .scrape/.work/{site_name}/explore 2 2")

这会下载起始页、最多 2 个详情页和最多 2 个列表页,对链接分类,并生成导航值。所有输出都写入 .scrape/.work/{site_name}/explore/。

如果子 Agent 报告站点被拦截,请调用 /scrape-zyte-login。返回后,重新运行上面的 scrape-explore-site 子 Agent。只有探索成功后才能继续。

然后将页面分发到相应的数据类型子文件夹:

mkdir -p {site_path}/{data_type}/pages {site_path}/navigation/pages {site_path}/navigation/values

# Detail pages → data type
for d in .scrape/.work/{site_name}/explore/pages/detail-*; do
  [ -d "$d" ] && cp -r "$d" {site_path}/{data_type}/pages/
done

# Start + list pages → navigation
for d in .scrape/.work/{site_name}/explore/pages/start-* .scrape/.work/{site_name}/explore/pages/list-*; do
  [ -d "$d" ] && cp -r "$d" {site_path}/navigation/pages/
done

# Navigation values (generated by explore-site)
cp .scrape/.work/{site_name}/explore/values/*.json {site_path}/navigation/values/ 2>/dev/null || true

步骤 3:确定导航 HTML 变体

分析详情页之前,需独立确定导航页面所需的 HTML 变体。对所有导航页面分别使用两种变体运行 extract_links.py:

mkdir -p .scrape/.work/{site_name}/analyze-nav

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/scripts/extract_links.py \
  {site_path}/navigation/pages/*/raw.html \
  --group --base-url-from-meta \
  > .scrape/.work/{site_name}/analyze-nav/nav.raw.json 2>/dev/null || true

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/scripts/extract_links.py \
  {site_path}/navigation/pages/*/rendered.html \
  --group --base-url-from-meta \
  > .scrape/.work/{site_name}/analyze-nav/nav.rendered.json 2>/dev/null || true

读取两个输出文件并分析链接分组。确定哪种 HTML 变体能更好地覆盖导航内容——考虑分组结构、每种变体中是否出现有意义的导航链接,以及其中一种变体是否能发现另一种遗漏的链接。除非有明确证据表明 rendered 能显著提升导航覆盖率,否则优先选择 raw。

将结果存储为 nav_html_variant,供步骤 6 使用。

步骤 4:并行分析详情页样本和列表页

首先,使用两种 HTML 变体分析一个有界的详情页样本。如果存在列表页,则使用第一个同时具有 raw.html 和 rendered.html 的详情页;否则使用前 1–2 个详情页。这意味着,如果同时分析列表页,详情页变体对比最多使用 1 个页面;如果没有可用的列表页,则最多使用 2 个页面。变体对比的详情页分析 Agent 不得超过 4 个。这样既能保持工作流响应迅速,又能测试原始 HTML 或渲染后的 HTML 是否能提取经批准的架构字段。

同时,使用原始 HTML 变体和数据类型架构,分析 {site_path}/navigation/pages/ 中的所有列表页。在同一条消息中启动详情页样本 Agent,以及每个列表页各自的一个 Agent,以并行执行。合计启动的 Agent 不得超过 5 个,以避免触及提供方的线程限制;如果存在列表页,优先选择 detail-1 的原始 HTML/渲染后 HTML 以及列表页 Agent,而不是再分析第二个详情页。请在同一条回复中发出所有 Agent 调用,中间不要调用任何工具——不要等待任何结果后再启动其余 Agent。

启动 Agent 前,创建输出目录:

mkdir -p .scrape/.work/{site_name}/analyze-page
mkdir -p {site_path}/{data_type}-list/values
Agent(description="analyze detail-1 raw", prompt="/scrape-analyze-page Extract data from {site_path}/{data_type}/pages/detail-1/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-1.raw.json ")
Agent(description="analyze detail-1 rendered", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-1/rendered.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-1.rendered.json")
Agent(description="analyze list-1", prompt="/scrape-analyze-page --list-mode Extract all {data_type} items from {site_path}/navigation/pages/list-1/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into {site_path}/{data_type}-list/values/list-1.json")
Agent(description="analyze list-2", prompt="/scrape-analyze-page --list-mode Extract all {data_type} items from {site_path}/navigation/pages/list-2/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into {site_path}/{data_type}-list/values/list-2.json")
... (all list pages in the same message)

If there are no list pages, add the second detail-page pair instead:

Agent(description="analyze detail-2 raw", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-2/raw.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-2.raw.json")
Agent(description="analyze detail-2 rendered", prompt="Run /scrape-analyze-page {site_path}/{data_type}/pages/detail-2/rendered.html using the schema in {site_path}/{data_type}/spec.json and save it into .scrape/.work/{site_name}/analyze-page/detail-2.rendered.json")

跳过 HTML 文件不存在的变体。如果 {site_path}/navigation/pages/ 中没有列表页,则跳过列表页 Agent,以及 {data_type}-list/values 的 mkdir。schema_path 会向 analyze-page 提供经批准的字段名、描述和示例,因此它能以正确的名称和格式提取值。步骤 5 选定变体后,不要再启动额外的详情页分析。无需等待所有列表页 Agent 完成后再继续:有界的详情页样本分析完成,且至少有一个列表页 values 文件可用后,就使用已完成的列表输出继续执行步骤 4.5,以免较慢的可选列表页分析阻碍最终定稿。

步骤 4.5:决定是否创建列表页数据类型

只有在步骤 4 中找到并分析了列表页时,才执行此步骤。

读取已完成的 {site_path}/{data_type}-list/values/list-*.json 文件。对于每个已完成的文件,检查架构中每个 source: "requested" 字段是否都作为键出现在 values 数组至少一个项目中。如果尚无列表页 values 文件完成,则将 list_spec_created = false,并继续进行详情页提取,而不是等待。

如果每个已完成的列表页 values 文件都包含所有请求字段:

设置 list_spec_created = true。

  1. 写入 {site_path}/{data_type}-list/spec.json:

    {
      "url": "{url}",
      "data_type": "{data_type}-list",
      "html_variant": "raw",
      "schema": {<same schema object as in {site_path}/{data_type}/spec.json>}
    }
    
  2. 将列表页复制到新的数据类型:

    mkdir -p {site_path}/{data_type}-list/pages
    for d in {site_path}/navigation/pages/list-*; do
      [ -d "$d" ] && cp -r "$d" {site_path}/{data_type}-list/pages/
    done
    

否则: 设置 list_spec_created = false。照常继续进行详情页提取——{data_type}-list/values/ 目录可以保留,但会被忽略。

步骤 5:选择 HTML 变体

比较 .scrape/.work/{site_name}/analyze-page/ 中限定样本的原始结果与渲染结果。

对于每个页面,比较 {page_id}.raw.json 和 {page_id}.rendered.json:

  • 哪个变体找到的模式字段更多?
  • 哪些字段仅存在于一个变体中?
  • 同一字段在不同变体中的值是否不同?

使用一个小型 Python 脚本进行比较。脚本应加载 {site_path}/{data_type}/spec.json,枚举 .scrape/.work/{site_name}/analyze-page/*.json,仅比较模式字段覆盖情况和值,打印简明摘要,并建议使用 raw,除非 rendered 持续找到 raw 未找到的所需模式字段。

默认优先使用 Raw——它更快、更省成本,也更可靠。仅当 rendered 能找到 raw 持续遗漏的模式字段,或原始 HTML 基本为空(SPA 网站)时,才使用渲染结果。

在终端中显示比较结果:

HTML variant comparison:
  Both variants found: name, price, brand, description, image_url
  Only in rendered: reviews_count (3/3 pages), sale_price (2/3 pages)
  Only in raw: (none)
  Value differences:
    price: raw="$29.99", rendered="$24.99" (detail-1) — rendered may show sale price

  Recommendation: raw (all schema fields found)
  Note: rendered also has reviews_count, sale_price — say "use rendered" if you need these.

如果能明确选择哪个变体,就使用该变体。如果无法确定,例如原始视图包含大多数但并非全部字段,则通过 AskUserQuestion 询问用户要使用哪个变体,并提供以下详情:

  • question:"提取时应使用哪个 HTML 变体?"
  • header:"HTML 变体"
  • options:"使用 raw" 和 "使用 rendered",并标记推荐选项。

在这种情况下,使用用户选择的变体。

如果两个变体都能在限定样本中找到所有已批准的模式字段,则立即选择 raw。如果所选变体与阶段 1 使用的变体不同,则使用新值更新 {site_path}/{data_type}/spec.json 中的 html_variant。选择变体后,直接继续步骤 6;不要启动更多分析 Agent。

步骤 6:提取值(如果 list_spec_created,则跳过)

如果 list_spec_created 为 true,则跳过此步骤——步骤 4 已将值写入 {data_type}-list/values/。

否则,使用 extract_values.py 根据分析文件构建值,并按模式进行筛选:

uv run ${CLAUDE_SKILL_DIR}/../scrape-explore-site/scripts/extract_values.py \
  .scrape/.work/{site_name}/analyze-page/ \
  {site_path}/{data_type}/spec.json \
  --variant {html_variant} \
  -O {site_path}/{data_type}/values/

这会用从已分析的详情页样本中新提取的内容覆盖所有现有值文件(包括阶段 1 的文件)。无需使用 --renames——阶段 2 的 analyze-page 会接收完整模式(名称 + 描述 + 示例),因此会直接使用正确的字段名进行提取。

导航

使用 ${CLAUDE_SKILL_DIR}/../scrape/references/extraction-spec.md 中的固定导航模式,结合网站 URL 和 nav_html_variant(在步骤 3 中确定),写入 {site_path}/navigation/spec.json。

导航值已在步骤 2 中从 explore-site 输出复制。

步骤 7:可选的浏览器审查

先告诉用户提取统计信息(“已为 {N} 个详情页和 {M} 个导航页提取值。”),然后通过 AskUserQuestion 询问用户是否需要进行浏览器审查。

如果环境无法提出后续问题,则跳过浏览器审查并继续。

  • question:"是否打开浏览器审查提取的值?"
  • header:"浏览器审查"
  • options:
    • 跳过浏览器审查 — "继续,不打开浏览器。"
    • 打开浏览器审查 — "在浏览器中审查这些值。"

如果用户选择 跳过审查,则转到步骤 9。

如果用户选择 打开浏览器审查,则使用数据类型模式调用 /scrape-review-schema:

/scrape-review-schema {site_path}/{data_type} .scrape/.work/{site_name} {schema_json} {html_variant}

打开审查目录前,先向用户报告其路径。

步骤 8:应用反馈

如果用户审核并提供了反馈:

如果反馈以 APPROVED 开头:应用其中包含的模式变更(删除、重命名、修改描述、保留字段 → 将来源更改为 "requested"),然后跳到步骤 9。用户已确认。

如果反馈不以 APPROVED 开头(用户点击了“请求修改”):

  • 直接应用模式变更(删除、重命名、修改描述)
  • 对于值的更正:先检查另一变体的分析文件。如果另一变体中的值正确,建议切换变体:
    You corrected price to "$24.99" — the rendered variant already extracts this correctly (across 3/3 pages).
    Switch to rendered? [Y/n]
    
    如果用户同意,切换变体、更新规范并重新生成值。
  • 如果另一变体没有帮助:使用选定的变体,针对所有详情页面重新分析更正后的字段。并行启动多个 Agent,每个页面一个。

重新分析或切换变体后,重新提取值(步骤 6),并再次提供审核。将变更摘要作为第 5 个参数传递给 /scrape-review-schema:

/scrape-review-schema {site_path}/{data_type} .scrape/.work/{site_name} {schema_json} {html_variant} '["Re-analyzed price across all pages","Dropped field isbn"]'

循环执行步骤 7–8,直到用户批准或跳过审核。

步骤 9:完成

根据审核中的模式变更,更新 {site_path}/{data_type}/spec.json(仅当 list_spec_created 为 false 时相关,因为此时使用了详情页面)。

更新 {site_path}/spec.json — 按如下方式设置 data_types:

  • 如果 list_spec_created 为 true:["{data_type}-list", "navigation"] — 省略 "{data_type}",因为不需要从详情页面提取数据。
  • 否则:["{data_type}", "navigation"]

报告:

如果 list_spec_created 为 true:

Spec finalized at {site_path}/:
  {data_type}-list: {N} list pages, {F} fields, {K} items extracted
  navigation: {M} pages

All requested fields found on list pages — skipping detail-page extraction.
Ready for codegen: /scrape-codegen {site_path}/{data_type}-list ./{project_dir}

否则:

Spec finalized at {site_path}/:
  {data_type}: {N} detail pages, {F} fields
  navigation: {M} pages

Ready for codegen: /scrape-codegen {site_path}/{data_type} ./{project_dir}

评论

支持 Markdown