站点 URL 数量上万以后,Sitemap 就不再是一个文件能装下的事。协议对单个 Sitemap 有明确上限:5 万条 URL、未压缩体积 50MB。超了不会报错,但多出来的部分会被直接忽略,等于白交。所以规模上去之后,分片和压缩不是优化技巧,而是必须做的事。
三条硬线先记住
- 单个 Sitemap 文件:URL 不超过 5 万条,未压缩体积不超过 50MB。
- 索引文件(sitemapindex):最多收录 5 万个 Sitemap,同样受 50MB 限制。
- 一个索引文件可以指向多个 Sitemap,但不能再套一层索引。
这三条是协议层面的约束,写错了大概率不会立刻看到报错,但蜘蛛会安静地丢掉超出部分。所以每次生成 Sitemap 时,最好在程序里加一道校验,超限就自动切分。
索引文件怎么写
分片之后需要一个入口把清单串起来,这就是 sitemapindex。它里面只放 <sitemap> 节点,每个节点一个 <loc>,可选的 <lastmod>。常见错误是把 <url> 标签混进索引文件,或者索引和分片互相引用,形成循环。
索引文件只负责指路,不负责列 URL。职责混在一起,出问题时最难排查。
压缩能省什么
Sitemap 支持 Gzip 传输,把文件命名为 .xml.gz 即可。需要注意的是,限制按未压缩体积计算,压缩只是减少传输带宽和下载耗时。对蜘蛛来说,一个 2MB 的压缩包比 20MB 的纯文本文件更容易在短时间内读完,这在实际抓取中是有意义的差别。
但压缩后别忘了几件事:索引文件里的 <loc> 必须指向压缩后的真实地址;服务器要正确返回 Content-Type: application/x-gzip(或 application/gzip),并且不能对 .gz 文件再做一层传输压缩,否则容易解压失败。
怎么切分才合理
切分方式没有唯一答案,但下面几种比“随机每 5 万条切一刀”更好维护:
- 按栏目切:文章、商品、分类、标签各一个文件。某个栏目出问题,影响范围可控。
- 按更新频率切:高频更新的新闻、商品价格单独成片,低频的静态页另一片。这样 lastmod 的信号更干净。
- 按语言或地区切:多语言站点按目录划分,便于分市场提交和统计。
- 保持归属稳定:同一个 URL 尽量长期待在同一个分片里,频繁搬家会让抓取统计对不上账。
几个容易踩的坑
- 分片文件的 <loc> 用相对路径。必须是完整绝对地址,含协议和域名。
- 索引文件里写 <url> 标签,或者索引指向索引。
- .gz 文件名和索引里写的地址不一致,等于交了一份读不到的清单。
- 全站所有 URL 的 lastmod 都填成同一个生成时间。这个字段是给蜘蛛判断“值不值得重抓”的参考,全站齐刷刷一个时间,等于没有信息。
- 分片文件没有对外可访问,被权限、伪静态规则或 CDN 缓存策略挡住,蜘蛛下载返回 403 或 404。
交出去之后做什么
Sitemap 是发现入口,不是抓取指令。提交之后要做的是核对:在服务器日志里看蜘蛛有没有真的去取这些分片文件,返回码是不是 200,取完之后是否顺着里面的 URL 走进来。如果日志里只看到取 Sitemap,却看不到后续的页面抓取,问题往往不在 Sitemap 本身,而在页面层的可达性、响应速度或 robots 规则。
另一件值得做的事是定期巡检:分片里是否存在大量 404、301 或者 noindex 的 URL。清单里混进太多无效地址,会稀释这份文件的价值,也会让蜘蛛多跑一趟空路。保持 Sitemap 与站内实际结构一致,比追求条数更重要。