关于 scrape-spec
scrape-spec 用于扩展并验证网站数据提取规范。它抽取详情页和列表页样本、比较 HTML 变体,并生成提取值与导航数据。
主要功能
- 01抽样详情页和列表页
- 02比较原始与渲染 HTML
- 03验证规范字段的提取值
- 04生成导航数据类型
适用场景
- 01扩展初始网站规范
- 02检查不同页面变体的提取结果
- 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——一个按原样使用的单一值:
- 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。
-
写入
{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>} } -
将列表页复制到新的数据类型:
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}