首页
/ Scrapling 如何用 SitemapSpider 基于 sitemap 自动发现并爬取整个站点

Scrapling 如何用 SitemapSpider 基于 sitemap 自动发现并爬取整个站点

2026-09-08 16:33:15作者:卓艾滢Kingsley

当你拿到一个站点的 sitemap.xml,想把它列出的所有页面批量抓下来,但又不想为每一类 URL 手写 parse() 样板代码时,Scrapling 的 spider 系统提供了现成的 SitemapSpider 模板:你只需声明 sitemap_urls 和一组基于 LinkExtractor 的规则,它会自动解析 sitemap(包括 sitemap 索引),把每个 URL 分发给第一个匹配的回调处理。本文按「安装 → 编写 spider → 运行 → 验证结果」的顺序走通这条路径,并覆盖 sitemap 索引、robots.txt 入口和多语言 alternate URL 三个可选分支。

前提条件:Python 3.10 或更高版本。

Spider 架构图

安装:spider 功能需要 fetchers 依赖

Scrapling 的裸装命令只包含解析引擎,不包含 fetchers 和 spiders 所需的依赖,此时 import scrapling.spiders 会抛 ModuleNotFoundError

pip install scrapling

使用 spider(包括 SitemapSpider)前必须安装 fetchers 依赖:

pip install "scrapling[fetchers]"

scrapling install           # 下载浏览器及其系统依赖
scrapling install  --force  # 强制重装

scrapling install 会下载所有浏览器及其系统依赖和指纹操作依赖;如果只走 HTTP 请求,这一步也是 fetchers 安装流程的一部分。安装完成后,from scrapling.spiders import SitemapSpider 才能正常导入。

SitemapSpider 如何分发 sitemap 里的 URL

理解分发规则,才能解释为什么某些 URL 没有出现在结果里。SitemapSpider 继承自 Spider,内部机制(见 generic-templates.mdsitemap.py):

  • start_urls 被换成 sitemap_urls:未设置 sitemap_urls 时,start_requests() 直接抛出 RuntimeError("SitemapSpider needs sitemap_urls to be set.")。
  • 每个 sitemap URL 先由内部的 _parse_sitemap 回调解析。遇到 <sitemapindex>(sitemap 的 sitemap)时,自动递归下载每个子 sitemap;遇到 <urlset> 时提取每个 <url><loc>
  • gzip 压缩的 sitemap(.xml.gz 或 gzip content-type)会被自动解压;XML 解析失败只记录一条 warning(如 "Failed to parse sitemap XML"),不会中断整个爬取。
  • 拿到 URL 列表后,SitemapSpider 按顺序用每条规则的 LinkExtractor.matches(url) 逐个检查,第一个匹配的规则获胜,该 URL 以这条规则的 callback 发出请求。
  • 有规则但没有任何规则匹配:该 URL 被丢弃。
  • rules() 返回空列表:所有 URL 路由到 spider 的 parse() 方法;parse() 默认实现会抛 NotImplementedError,所以要么写规则,要么自己覆写 parse()

LinkExtractor 的 URL 过滤参数(来自 generic-templates.md 的参数表):

参数 默认值 说明
allow () 保留的 URL 模式,空表示匹配全部
deny () 丢弃的 URL 模式,永远优先于 allow
allow_domains () 保留的主机名,子域自动匹配
deny_domains () 丢弃的主机名
deny_extensions IGNORED_EXTENSIONS 丢弃的文件扩展名(pdf、zip、图片、视频等)

注意 deny_extensions 有默认值:即使 allow 匹配,带 pdf、zip、图片等扩展名的 sitemap URL 也会被丢弃。

编写并运行一个 SitemapSpider

以下代码结构来自 generic-templates.md 的官方示例。使用前需要替换:sitemap_urls 换成目标站点的真实 sitemap 地址,rules() 里的 allow 正则和回调选择器按你的站点结构调整。

from scrapling.spiders import SitemapSpider, CrawlRule, LinkExtractor

class MySitemap(SitemapSpider):
    name = "sm"
    sitemap_urls = ["https://example.com/sitemap.xml"]

    def rules(self):
        return [
            CrawlRule(LinkExtractor(allow=r"/posts/"), callback=self.parse_post),
            CrawlRule(LinkExtractor(allow=r"/products/"), callback=self.parse_product),
        ]

    async def parse_post(self, response):
        yield {"title": response.css("h1::text").get()}

    async def parse_product(self, response):
        yield {"sku": response.css(".sku::text").get()}

result = MySitemap().start()

几个要点:

  • 回调必须是 async generator(async def + yield),与普通 Spider 一致。
  • CrawlRulecallback 外还支持可选的 priority 覆盖和 process_request(在请求发出前修改它)。
  • start() 内部处理全部异步机制,爬取过程会记录到终端,结束后返回 CrawlResult 对象。

验证爬取结果

start() 返回的 CrawlResult 是判断是否成功的依据(见 getting-started.md):

result = MySitemap().start()

# 爬完还是被暂停了?
print(f"Completed: {result.completed}")

# 访问抓到的条目
for item in result.items:
    print(item)

# 查看统计
print(f"Scraped {result.stats.items_scraped} items")
print(f"Made {result.stats.requests_count} requests")
print(f"Failed: {result.stats.failed_requests_count}")
print(f"Took {result.stats.elapsed_seconds:.1f} seconds")

条目可以用内置方法直接导出,父目录不存在时会自动创建:

result.items.to_json("sm.json", indent=True)   # JSON
result.items.to_jsonl("sm.jsonl")              # 每行一个 JSON 对象
result.items.to_csv("sm.csv")                  # CSV
result.items.to_xml("sm.xml")                   # XML

判断爬取是否正常,看三件事:result.completed 是否为 TrueFalseresult.pausedTrue 说明被 Ctrl+C 暂停,可重新运行恢复);stats.failed_requests_count 有多少失败请求;stats.items_scraped 是否接近你预期的 sitemap 条目数。如果发现 sitemap 里的 URL 数量明显多于实际请求数,通常是有 URL 没匹配任何规则被丢弃了,回去检查 rules()allow 正则和 deny_extensions 默认过滤。

完整统计清单(状态码分布、被 robots.txt 拦截数、按域的字节数等)见 advanced.md 的 "Results & Statistics" 一节。

可选分支:三种 sitemap 入口与过滤

只爬部分子 sitemap(sitemap 索引)

当根 sitemap 是 <sitemapindex> 时,SitemapSpider 默认递归进入所有子 sitemap。用 sitemap_follow 指定一个 LinkExtractor,只进入匹配的子 sitemap(None 表示进入全部):

class MySitemap(SitemapSpider):
    name = "sm"
    sitemap_urls = ["https://example.com/sitemap.xml"]
    sitemap_follow = LinkExtractor(allow=r"/posts-sitemap-\d+\.xml")  # 只进文章 sitemap

用 robots.txt 作为入口

把 robots.txt 地址直接放进 sitemap_urlsSitemapSpider 会识别它,提取其中所有 Sitemap: 指令并逐个跟进:

class MySitemap(SitemapSpider):
    name = "sm"
    sitemap_urls = ["https://example.com/robots.txt"]

如果 robots.txt 里没有 Sitemap 指令,会记录一条 "No Sitemaps found in ..." 的 warning,爬取不会拿到任何 URL。

爬多语言版本页面

设置 sitemap_alternate_links = True<xhtml:link rel="alternate" hreflang="..."> 中的地址也会被提取并同样走 rules() 分发:

class MySitemap(SitemapSpider):
    name = "sm"
    sitemap_urls = ["https://example.com/sitemap.xml"]
    sitemap_alternate_links = True

限制与边界

  • 未设置 sitemap_urls 会直接抛 RuntimeError,不存在其他默认入口。
  • 有规则时,不匹配任何规则的 sitemap URL 被静默丢弃;sitemap 里的 PDF、图片等静态资源 URL 受 deny_extensions 默认值影响同样会被丢弃。
  • sitemap 本身损坏(gzip 解压失败或 XML 语法错误)只产生 warning 并跳过该 sitemap,需要到爬取日志里找 "Failed to decompress sitemap" / "Failed to parse sitemap XML" 来定位是哪个 sitemap 没被解析。
  • 如果站点还有 robots.txt 抓取限制,可以像普通 spider 一样设置 robots_txt_obey = True,被 Disallow 的请求会计入 stats.robots_disallowed_count
  • 大站点爬取被中断时,可通过构造参数 crawldir 启用检查点机制(暂停/恢复、断点续爬),用法见 advanced.md 的 "Pause & Resume" 一节。

更多 spider 能力(并发控制 concurrent_requests/download_delay、AutoThrottle、流式输出 stream()、生命周期钩子)参考 advanced.md;如果不用模板、想在自己的 Spider.parse() 里直接取链接,LinkExtractor 也可以单独使用,示例同在 generic-templates.md

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391