关于 scrape-codegen
面向 Scrapy 项目的 Claude skill,可依据提取规范和已保存的 HTML 样本生成并测试 web-poet 页面对象。
主要功能
- 01生成页面对象框架
- 02分析已保存的 HTML 页面
- 03生成基于 schema 的提取代码
- 04转换 fixtures 并运行测试
适用场景
- 01根据提取规范创建页面对象
- 02生成列表页提取代码
- 03使用已保存的 fixtures 测试提取
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ zytedata/ skills --skill scrape-codegen安装后在 Claude Code 中输入/scrape-codegen确认已加载。
附带文件scripts/convert_fixtures.py
详细介绍
你正在根据提取规范生成一个 web-poet 页面对象。规范包含架构、已保存的 HTML 页面和预期值。它可以描述任何数据类型,例如产品详情、导航链接、文章内容等。Codegen 无需了解数据类型;它会根据架构生成提取数据的 PO。
规范由 /scrape-spec 生成,项目由 /scrape-ensure-project 创建。
阅读 ${CLAUDE_SKILL_DIR}/../scrape/references 中的 python-environments.md 和 docs-access.md。
输入
原始参数字符串为 $ARGUMENTS。将其拆分为最多 3 个以空格分隔的位置参数:
- spec_path:规范文件夹的路径,例如
.scrape/books-toscrape - project_dir:Scrapy 项目的路径
- fields:可选,以逗号分隔的待生成字段名称(留空 = 所有字段)
流程
步骤 1:读取规范
读取 {spec_path}/spec.json,获取:
schema.properties— 字段定义html_variant— 要使用的 HTML(raw或rendered)url— 起始 URL(用于域名)data_type— 要提取的数据类型(用于类命名);始终使用单数形式(例如product、book)
根据以下约定,从 data_type 派生名称(不要使用复数形式):
ClassName= PascalCase +Page→product→ProductPageItemClass= PascalCase +Item→product→ProductItemmodule_name=data_type的 snake_case →product→product
如果提供了 fields,则只保留 schema.properties 中对应的字段。
列出 {spec_path}/pages/ 中与 {spec_path}/values/ 中的值相对应的页面目录。读取每个页面的预期值。
从 spec_path 派生 site_name(取父目录名称,例如从 .scrape/books-toscrape/products 中得到 books-toscrape)。
从 {project_dir} 检测项目名称。
列表类型检测。 如果 data_type 以 -list 结尾(例如 products-list):
- 设置
is_list_type = true - 去掉
-list后缀,得到base_type(例如products) - 派生
ItemClass:如果base_type以s结尾,则去掉末尾的s将其变为单数(例如products→product),然后使用 TitleCase(例如Product)。如果名称看起来已经是单数,则直接使用 TitleCase。 WrapperClass = {ItemClass}ListItems(例如ProductListItems)PageClass = {ItemClass}ListPage(例如ProductListPage)- 值采用数组格式:
{"url": ..., "values": [{...}, ...]}
否则,设置 is_list_type = false,并将 ClassName 派生为 TitleCase(data_type) + "Page"。
步骤 2:添加 item 和 page object 存根
对于非列表类型(is_list_type = false):
检查 {project_name}/items.py 中是否存在与 data_type 匹配的 item 类。
如果不存在,则根据架构编写一个(所有字段均为可选,使用 | None = None)。
在子 Agent 中添加 page object 存根,以便父技能之后继续执行:
Agent(description="add page object stub", prompt="/scrape-add-page-object {project_dir}/{project_name}/pages/{module_name}.py {ClassName} {domain} web_poet.WebPage {project_name}.items.{ItemClass}")
如果 html_variant 是 rendered,则使用 web_poet.BrowserPage。
对于列表类型(is_list_type = true):
items.py 需要包含两个类。检查它们是否已存在;缺少的类都要补上。
-
基础 item 类(
ItemClass,例如Product)——一个@dataclass,字段类型与架构匹配。示例:@dataclass class Product: title: str price: str | None = None -
包装类(
WrapperClass,例如ProductListItems)——一个@dataclass,包含唯一的items字段,其类型为list[ItemClass] | None = None。示例:@dataclass class ProductListItems: items: list[Product] | None = None
然后在子 Agent 中添加 page object 存根,并明确将 items 作为第 6 个参数传入,以便生成 @field 存根,即使所有包装类字段都有默认值:
Agent(description="add page object stub", prompt="/scrape-add-page-object {project_dir}/{project_name}/pages/{module_name}.py {PageClass} {domain} web_poet.WebPage {project_name}.items.{WrapperClass} items")
步骤 3:转换 fixture
从项目结构中查找 fixture 类路径(例如,
{project_name}.pages.{module_name}.{ClassName})。
uv run ${CLAUDE_SKILL_DIR}/scripts/convert_fixtures.py \
{spec_path} {project_dir} {fixture_class_path}
步骤 4:分析页面(并行)
mkdir -p .scrape/.work/{site_name}/codegen-analyze
每个页面启动一个 Agent,并提供对应的值,在一条消息中全部发送以并行执行。每个 Agent 都会运行 /scrape-codegen-analyze,并接收全部 4 个参数:
/scrape-codegen-analyze {spec_path}/pages/{page_id}/{html_variant}.html .scrape/.work/{site_name} {spec_path}/spec.json {spec_path}/values/{page_id}.json
跳过 HTML 文件不存在的页面。
对于列表类型的规格,页面名称以 list-* 开头,值中包含数组。
/scrape-codegen-analyze 技能会根据 meta.json(其中 page_type 为 list)自动检测列表页面,并生成基于容器的提取说明。
步骤 5:生成页面对象代码
所有分析 Agent 完成后,启动一个 Agent 运行 /scrape-codegen-generate,并接收全部 3 个参数:
/scrape-codegen-generate .scrape/.work/{site_name} {project_dir}/{project_name}/pages/{module_name}.py {spec_path}/spec.json
步骤 6:测试
cd {project_dir} && uv run pytest fixtures/ -x -v
报告结果。如果测试失败,请阅读错误信息,并考虑重新生成失败的字段。
步骤 7:报告
Generated page object at {project_dir}/{project_name}/pages/{module_name}.py:
Class: {ClassName} (N fields)
Fixtures: N test cases
Tests: N/N passing
代码生成规则
遵循 ${CLAUDE_SKILL_DIR}/../scrape/references/web-poet.md 中的 web-poet 参考指南,并遵守以下规则:
- 保持代码简洁且适用于不同领域,不要过度适配示例页面
- 缺少数据时返回
None,不要返回空字符串、False或[] - 使用保护子句,并在访问属性前检查是否为
None - 不要为字段方法添加文档字符串
- 不要捕获通用的
Exception,只捕获特定异常 - 尽量保证输出确定性,避免使用集合(如有需要,使用列表并去重)
- 如果分析显示某个字段来自结构化数据(JSON-LD、microdata),请使用
extruct——元数据格式与前序阶段extract_metadata.py的输出一致,因此页面对象中可以使用相同的访问模式 - 如果需要浏览器响应,请将
BrowserPage用作基类