关于 scrapy-extra
scrapy-extra 是面向 Scrapy 开发者的技能,用于编写或修改 spider、页面对象、item、pipeline 和设置。它按任务提供实现与测试指引,并在适用的新项目中优先采用 web-poet 页面对象。
主要功能
- 01编写和调试 Scrapy 组件
- 02在适用的新 spider 中使用 web-poet 页面对象
- 03按任务查阅 Scrapy 参考资料
- 04用 fixture 测试页面对象
- 05通过限量抓取和检查条目验证 spider
适用场景
- 01创建 Scrapy 项目或 spider
- 02修改现有爬虫的抽取逻辑
- 03使用已保存页面的 fixture 测试页面对象
- 04排查抓取输出中的缺失或错误字段
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ zytedata/ skills --skill scrapy-extra安装后在 Claude Code 中输入/scrapy-extra确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/project-template/cookiecutter.jsonassets/project-template/{{cookiecutter.project_name}}/pyproject.tomlscrapy.cfgassets/project-template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/__init__.pyitems.pysettings.pyassets/project-template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/pages/__init__.pyassets/project-template/{{cookiecutter.project_name}}/{{cookiecutter.project_name}}/spiders/__init__.pyassets/project-template/{{cookiecutter.project_name}}/fixtures/.gitkeepreferences/scrapy-poet.mdscrapy-zyte-api.mdscrapy.mdweb-poet.md详细介绍
此文件共 172 行;请全部阅读。
以下的 SKILL_DIR 表示包含此文件的目录的绝对路径。
你正在进行 Scrapy 实际编码:编写或修改爬虫、页面对象、条目、管道、设置或整个项目。
对于新建爬虫,优先使用 web-poet 页面对象——将提取逻辑隔离开来,能让爬虫专注于抓取,也更易于维护、测试和重用。具体采用到什么程度取决于项目:
- 全新项目,或已配置 scrapy-poet 的项目:除非另有说明,否则使用页面对象。
- 已有爬虫但未使用 scrapy-poet 的项目:建议添加 scrapy-poet 支持(除非用户已表示不想添加),而不要擅自假定要添加;普通爬虫(生成字典或条目)是备选方案。
除非用户提出要求,否则不要将现有爬虫迁移到页面对象,也不要在未使用 web-poet 的项目中添加它。
不要重新实现 Scrapy 已有的功能:爬虫不需要已访问 URL 集合,因为去重过滤器会自动丢弃重复请求。
没有固定的工作流,也没有必需的输入或输出。阅读任务,阅读下面相关的参考资料,然后编写符合惯例的代码。
参考资料
随附于 SKILL_DIR/references/ 中——只阅读任务所需的资料,根据你即将编写的内容选择;大多数任务只需要一份:
- 编写或调试爬虫、条目、管道、选择器、Feed 导出或设置 →
scrapy.md。 - 编写或调试页面对象,或保存并运行其测试夹具 →
web-poet.md。 - 编写以页面对象或条目为参数的爬虫回调(
handle_urls、DummyResponse、SCRAPY_POET_DISCOVER)→scrapy-poet.md;注入哪一种对象,是决定回调形式的关键。 - 网站会拦截请求或需要 JavaScript →
scrapy-zyte-api.md。
除此之外,请查阅官方文档,不要凭猜测作答:docs.scrapy.org、web-poet.readthedocs.io、scrapy-poet.readthedocs.io、scrapy-zyte-api.readthedocs.io、docs.zyte.com。这些文档适合大模型使用:将任意 URL 中的 .html 替换为 .md 即可获取 Markdown 版本,并查看 <host>/llms.txt 获取目录。
环境
所有 Python 执行都使用 uv——绝不要直接使用 python 或 pip。如果缺少 uv,请安装。
cd PROJECT_DIR && uv run scrapy crawl <name>
cd PROJECT_DIR && uv run --with pytest python -m pytest fixtures/
pytest 命令适用于包含 fixtures/ 目录的项目;没有该目录时无需运行任何内容。
.venv/、uv.lock、*.egg-info 和 build/ 都是预期的项目状态,并非临时文件:请保留它们。运行命令后留下的文件也是如此——.pytest_cache/、__pycache__/、测试抓取生成的 items.jsonl:不要费心查找并清理。
创建项目
仅当任务需要全新项目时才创建。使用随附的模板——其中已配置 scrapy-poet 和 Zyte API 插件的 settings.py,并提供 pages/、spiders/ 和 fixtures/ 目录:
uvx cookiecutter --no-input SKILL_DIR/assets/project-template \
-o PARENT_DIR project_name=PROJECT_NAME
cd PARENT_DIR/PROJECT_NAME && uv sync
对于现有项目,请在项目内操作。如果 pyproject.toml 缺少你所需的依赖项,请告知用户缺少什么并征求同意后再添加——不要悄悄重写他们的项目。
编写提取代码
无论是在爬虫回调中,还是在页面对象的 @field 中,默认都遵循以下指南,除非它们与其他已知的项目指南相冲突:
- 保持简单且通用,不要针对你查看过的特定页面过度拟合(不要硬编码标题,也不要按页面编写
if/else)。 - 有多个示例页面时,请用所有页面检查提取结果,而不只是第一个页面;只适用于你碰巧打开的页面的选择器属于过度拟合。如果页面之间存在差异,请优先使用更通用的选择器,或采用回退方案(例如先用 JSON-LD,再用 CSS)。
- 缺少数据时返回
None,不要返回""或False。 - 访问属性前先进行保护性检查;确认值不为
None。 - 不要捕获裸
Exception,只捕获你预期的特定异常。唯一的例外是遍历列表项时进行逐项提取:此时,在每个列表项的处理范围内捕获Exception,以免一个损坏的列表项导致其余项无法处理,并使用exc_info=True记录日志(参见web-poet.md→ 嵌套项提取)。 - 优先保证输出确定性(避免使用集合;必要时对列表去重)。
- 有结构化数据时优先使用:用
extruct处理 JSON-LD / microdata / OpenGraph,用jmespath查询 JSON,用price_parser解析价格。 - 只有当数据需要 JavaScript 时才请求浏览器渲染。使用页面对象时,将此需求声明为页面对象的输入——继承
BrowserPage,即依赖BrowserResponse——而不是通过 automap 参数或custom_settings启用browserHtml。不使用页面对象时,仅对需要渲染的请求逐个通过meta={"zyte_api_automap": {"browserHtml": True}}请求(参见scrapy-zyte-api.md)。
提取只负责提取,绝不负责筛选。 即使用户要求按值排除或限制结果,也不要在页面对象或提取方法中加入这类逻辑。筛选、去重和验证应放在爬虫或条目管道中;如果项目尚无这两者,则完全不要添加筛选逻辑,而不是将其移入页面对象。如果请求隐含了其他要求,请在摘要中说明。
测试
-
页面对象:运行
to_item()并与预期值比较来验证,而不是孤立地测试选择器,因为@field方法、Returns和输出处理会将原始选择器值转换为最终字段。将其作为由 pytest 检查的 web-poet fixture 来测试:它会运行真实的页面对象,对HttpResponse和BrowserResponse页面采用相同的方式,并留下回归测试。根据你手头的输入构建 fixture:- 有实时 URL →
uv run scrapy savefixture <page.object.ClassPath> '<url>'。 - 只有已保存的 HTML 样本(没有 URL)→ 根据每个文件构建输入,并使用
web_poet.testing.Fixture.save保存 fixture(代码片段见web-poet.md→ Testing,其中也涵盖BrowserResponse)。
将每个
output.json设置为人工核验过的预期值(修正savefixture的记录,或将其作为item=传给Fixture.save),然后运行uv run --with pytest python -m pytest fixtures/——它会对每个已保存页面重新运行to_item(),如果字段发生变化就会失败。完整流程见web-poet.md→ Testing。 - 有实时 URL →
-
爬虫:运行范围受限的测试爬取,并检查条目,不要只看退出码是否正常。始终使用
CLOSESPIDER_ITEMCOUNT或CLOSESPIDER_PAGECOUNT限定范围;少量条目就足以判断提取是否有效,验证爬虫时绝不需要完整爬取整个网站:cd PROJECT_DIR && uv run scrapy crawl <name> -s CLOSESPIDER_ITEMCOUNT=5 -o items.jsonl阅读
items.jsonl。如果某个字段始终为null,或值看起来不对,通常问题出在选择器上。如果原始 HTML 实际上只是 JavaScript 外壳,就切换到浏览器渲染后的输入(BrowserPage),并重新保存其 fixture——已保存的输入与记录时页面对象所依赖的内容一致。如果问题属于当前工作范围,即使根源在页面对象而非你被要求编写的爬虫中,也要修复根因。每次修复后,都要重新运行爬取并再次阅读items.jsonl,确认该字段现在已有值——退出码正常或关闭统计信息块都不能证明修复有效;也绝不要报告你未在当前运行输出中看到的字段值。如果某个字段一直为
null,且未对此作出说明,就绝不要声称爬虫已完成:要么修复它,要么在最终答复中说明原因——修复不在工作范围内,或页面上确实没有这些数据。无论哪种情况,都要指出受影响的字段。