sitemap 里的 priority 和 changefreq 到底有没有用:60 天抓取数据对照

2026-10-03 01:22:28 0 次浏览
SEOsitemapGoogle Search Console百度搜索资源平台技术SEO

适用读者:管企业官网、B2B 产品站的开发者或市场技术同学。如果你正纠结 sitemap 里那两个权重字段要不要认真填、值不值得写个后台去维护,这篇 60 天的对照数据可以直接帮你省掉这事儿。

一个制造业 B2B 官网,产品页 480 多条,sitemap 里 priority 全部填了 0.8,changefreq 写的是 weekly,发布后三个月,Google Search Console(GSC)里这些页面的抓取频次曲线几乎是一条直线,百度那边同样安静。8 月中旬我们把这个站的 sitemap 拆成两组做受控对照,跑满 60 天,结论比想象中干脆:Google 明确忽略 priority 和 changefreq,百度对 lastmod 敏感得多,对 changefreq 的反应小到可以忽略。真正把抓取拉起来的,是内链结构和真实的更新动作。

下面把实验做法、数据、以及 sitemap 到底该怎么生成,一次讲清楚。

这事儿是怎么起头的

这家做工业密封件的客户,官网是老 ASP.NET 项目,2024 年底迁到 .NET 8,sitemap 一直是手写的静态文件。市场部听了一场网站优化分享,回来要求"把 sitemap 的权重调一调,让抓取快点",于是有人连夜把 480 个产品的 priority 全改成了 0.9。改完一个月,抓取数据纹丝不动,才找到我们。

sitemap priority 与 changefreq 的 60 天抓取对照

先看他们站上原本的两条硬伤:

  • 内链:产品详情页只有导航和底部链接,同类产品之间互相不通,蜘蛛进来一条路走到黑。
  • lastmod:静态 sitemap 是 2024 年生成的,所有 lastmod 都是同一个日期,和页面真实更新时间对不上。

这两点在动手之前就得记下来,因为它们后面会变成对照组的变量。蜘蛛(搜索引擎爬虫,Crawler)对抓取预算(Crawl Budget)的分配,参考的从来不是你在 XML 里声明的愿望,而是它自己观测到的事实:这个页面有多少链接指着它、它上次来的时候内容变没变。

实验设计:分组与观察口径

改造思路很直接——不做花活,把变量拆干净。480 个产品页按产品线分成 A、B 两组,各 240 条,规模接近、页面模板一致、发布时间跨度接近。8 月 16 日上线新版 sitemap,两组同时生效。

项目 A 组(240 条) B 组(240 条)
priority 按产品线分层:主力线 0.9,配件 0.5 字段直接删除
changefreq 主力线 daily,配件 monthly 字段直接删除
lastmod 从 CMS 修订时间真实读取 同样真实读取
观察窗口 8/16 - 10/14,共 60 天 同左

观察指标两边各取一头:Google 用 GSC 的"设置 → 抓取统计信息"里的每日抓取请求量和"已抓取的网页"数;百度用搜索资源平台的"抓取频次"和"普通收录"曲线。为了排除干扰,这 60 天里站上不做大改版,robots 和 CDN 配置不动,外链投放也停掉。

还有一点要说在前面:A 组那套 priority 分层不是我们推荐的写法,它就是实验变量本身。对照组的意义就是让"填了权重字段"和"没填权重字段"打个照面。

60 天数据:Google 这边说得很直白

GSC 抓取统计是 2024 年才开放每日粒度的功能,看 8 月到 10 月的曲线,两组几乎贴在一起走,日均抓取请求从改造前的 210 次爬到第 6 周的 480 次左右,但 A、B 两条线之间的差异全程没超过 5%,都在日波动的噪声范围里。

指标 改造前(7 月) 第 2 周 第 6 周 第 8 周末
日均抓取请求(全站) 210 290 480 465
每日平均下载量 6.8 MB 9.1 MB 15.2 MB 14.7 MB
240 页中已被抓取比例(A 组) 54% 61% 83% 88%
240 页中已被抓取比例(B 组) 51% 60% 81% 86%
两组差异 — 1% 2% 2%

这个结果和 Google 的官方口径完全对得上:sitemaps.org 协议文档里写 priority 是"相对于本站其他 URL 的优先级",但 Google 的开发者文档在 sitemap 说明里直接写了它会忽略 <priority> 和 <changefreq> 的值。你在 XML 里写的权重,在 Google 的抓取调度器那里根本不进决策链路。那两个月抓取量翻了 2.2 倍,真正对应的动作是第 3 周我们把同类产品页的关联链接加上去了——每页底部新增 8 条"相关产品",第 4 周又把面包屑改成真实的分类路径。内链密度上来之后,曲线才抬头的。

百度这边本来期望会不一样,实际也有一点不一样的成分,但方向要修正。

60 天数据:百度认 lastmod,不认 changefreq

百度搜索资源平台的抓取频次曲线波动更大,日峰值能到日均的两三倍,所以看的是周均值。两组的 lastmod 都真实了之后,百度这边出现了 Google 那边没有的现象:lastmod 更新过的页面,一周内被抓到的比例明显高。

指标 改造前(7 月) 第 2 周 第 6 周 第 8 周末
周均抓取频次(全站) 1,150 1,420 2,050 1,980
lastmod 更新后 7 天内被抓到的页面占比(A 组) — 34% 51% 55%
lastmod 更新后 7 天内被抓到的页面占比(B 组) — 32% 49% 54%
A、B 两组差异 — 2% 2% 1%

分三层说这个表:

  • lastmod 真实化带来的收益是实打实的。以前全站 lastmod 一个日期,等于告诉百度"没有页面变过";改成真实修订时间后,7 天内新 lastmod 页面的抓取命中率从不到两成爬到五成上下。
  • priority 和 changefreq 在百度侧同样没有显示出信号。A 组填了分层权重和更新频率,B 组全删,两条曲线的差距始终在噪声以内。我们没有从数据里看出"百度参考 changefreq"的证据,网上流传的"百度看 changefreq"说法,至少在这个量级的站上没观测到。
  • 百度对"真实更新"的反应比 Google 更快。第 5 周客户上了一批新产品页(不在原 480 条里),lastmod 当天生效,百度侧 3 天内开始抓新页,GSC 侧是第 9 天。这个差异比较稳定,也符合两家引擎抓取节奏的一贯印象。

有一处数据要坦白:第 4 周百度抓取频次有一个异常尖峰,排查下来是 CDN 回源配置改错导致一批页面返回了旧内容加 200 状态码,百度连抓了两天。这条异常已经剔除出均值,但它在日志里提醒了我们一件事——抓取统计要配合访问日志看,光看平台曲线容易把事故当增长。

抓取调度机制:为什么这两个字段说不上话

要理解 priority 为什么没用,得把蜘蛛的决策过程拆开看。搜索引擎对单个站点的抓取不是"来了就全扫一遍",而是一个持续运转的调度循环。

flowchart TD
    A[待抓取 URL 队列] --> B{优先级打分}
    B --> C1[内链发现路径与锚文本]
    B --> C2[历史抓取经验: 上次内容是否变化]
    B --> C3[站点整体质量与抓取配额]
    C1 --> D[合成抓取优先级]
    C2 --> D
    C3 --> D
    D --> E[执行抓取]
    E --> F{内容有变化?}
    F -->|有| G[进入索引 更新 lastmod 认知]
    F -->|没有| H[记录未变 拉长下次回访间隔]
    G --> A
    H --> A

关键在打分这一步。调度器用的"优先级"是引擎自己算出来的,输入信号包括:这个 URL 被站内多少页面链接、链接出现在什么位置、上次抓取时内容哈希变没变、整个站的抓取配额还剩多少。XML sitemap 里的 priority 是站长的一面之词,引擎没法验证也不打算验证,Google 干脆在文档里写明忽略。百度没有像 Google 那样白纸黑字声明,但行为上这个字段的存在感约等于零。

changefreq 的处境更尴尬一点。它是站长对"未来"的承诺,而调度器关心的是"过去"——你上次说 weekly,页面 40 天没变,这个字段就从一个信号变成了一个需要打折的噪声源。反过来,lastmod 是对"过去"的陈述,可以被抓取结果校验:你写 10 月 1 日更新,蜘蛛 10 月 3 日来抓,发现内容确实变了,这个字段的信用就累积起来了。这就是为什么同样的字段,lastmod 有用而 changefreq 没用——一个可验证,一个不可验证。

sitemaps.org 协议本身对这三个字段的定义是"提示(hint)而非指令",也就是说协议层面就没保证引擎会照办。Google 选择了直接忽略其中两个,百度选择了靠抓取结果给 lastmod 建立信任。

sitemaps.org 的角色可以这样画出来:

sequenceDiagram
    participant G as sitemap 生成器(.NET 8)
    participant S as sitemap.xml
    participant P as 平台(提交入口/自动发现)
    participant C as 调度器与队列
    G->>S: 按真实 lastmod 生成 XML
    S->>P: 引擎读取或平台手动提交
    P->>C: URL 进入待抓队列
    C->>C: 按内链/历史/配额打分排序
    C->>S: 回来抓取并校验 lastmod 是否属实
    Note over C: 校验通过的站点 lastmod 信用升高<br/>priority/changefreq 不参与打分

sitemap 生成建议:别调权重,把 lastmod 写准

60 天实验换来的实操结论就一句话:sitemap 生成逻辑里,值得花力气的只有 lastmod 的准确性,priority 和 changefreq 直接不输出,省事。

lastmod 的"准确"有个容易翻车的坑:不能拿文件的修改时间,也不能拿缓存刷新时间,得拿内容的真实修订时间。我们的做法是在产品表里加一个 content_updated_at 字段,只有内容字段(标题、正文、参数表、图片)变更时才更新它,页面样式改动不碰这个字段。下面是 .NET 8 里的生成代码,无第三方依赖,用内置的 System.Xml.Linq 就够:

// 环境:.NET 8 控制台/后台任务,依赖 System.Xml.Linq(BCL 内置,无需 NuGet)
using System.Xml.Linq;

public class SitemapBuilder
{
    // 站点根域名,生产环境从配置读取
    private const string BaseUrl = "https://www.example.com";

    // 入参只带 Slug 和内容修订时间,字段越少越不容易把 priority 塞回来
    public XDocument Build(IEnumerable<ProductPage> pages)
    {
        var ns = XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9");
        // urlset 根节点,xmlns 必须是 sitemaps.org 0.9,百度和 Google 都认这套
        // 只输出内容真实变更过的页面,旧 URL 沉在 sitemap 里只会摊薄抓取配额
        var urlset = new XElement(ns + "urlset");

        foreach (var p in pages)
        {
            // loc 必须是带协议的完整 URL,相对路径会被引擎整条丢弃
            var lastmod = p.ContentUpdatedAt.ToUniversalTime()
                                  .ToString("yyyy-MM-ddTHH:mm:ssZ");
            var url = new XElement(ns + "url",
                new XElement(ns + "loc", $"{BaseUrl}/products/{p.Slug}"),
                // W3C Datetime 格式带时区,写错格式整条记录会被忽略
                new XElement(ns + "lastmod", lastmod));
            // priority / changefreq 一行都不写——Google 明确忽略,百度观测不到收益
            urlset.Add(url);
        }
        // 声明版本与编码,XML 头缺失在部分解析器上会报警
        var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), urlset);
        return doc;
    }
}

    // 实体类:ContentUpdatedAt 由 CMS 在内容字段变更时写入
    // 样式调整、缓存刷新一律不更新这个字段,否则 lastmod 会失真
    public record ProductPage(string Slug, DateTimeOffset ContentUpdatedAt);

sitemap 超过 5 万条 URL 或 50 MB 时要拆文件再用 sitemap index 汇总,这家站 480 条还用不上,但生成器写成可扩展的比较稳妥——用后台任务定时生成加 gzip 压缩,跑在 ASP.NET Core 的 hosted service 里:

// 注册方式:Program.cs 里 AddHostedService<SitemapJob>(),.NET 8 内置
// 依赖:ASP.NET Core 8,无第三方包
public class SitemapJob(IServiceScopeFactory scopeFactory) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        // 每 6 小时跑一次,产品内容变更由事件触发生成,这里只做兜底
        var timer = new PeriodicTimer(TimeSpan.FromHours(6));
        while (await timer.WaitForNextTickAsync(ct))
        {
            using var scope = scopeFactory.CreateScope();
            var repo = scope.ServiceProvider.GetRequiredService<IProductRepo>();
            // 只输出 90 天内有内容变更或新发布的页面,控制 sitemap 体积
            // lastmod 由 repo 直接带出,保证和 CMS 修订时间一致,不二次加工
            var pages = await repo.GetActivePagesSinceAsync(
                DateTimeOffset.UtcNow.AddDays(-90), ct);
            var xml = new SitemapBuilder().Build(pages);
            // 写入 wwwroot 并 gzip,同时更新 robots.txt 里的 Sitemap: 行
            await XmlSitemapStore.WriteAsync(xml, ct);
        }
    }
}

改造前后的 sitemap 生成策略对一下,差异其实就集中在两个字段和一条数据链路上:

项目 改造前 改造后
生成方式 手写静态文件,一年不更新 后台任务按内容事件生成
lastmod 来源 全站固定一个日期 CMS 内容字段真实修订时间
priority/changefreq 全填,权重手调 不输出
提交方式 仅靠 robots.txt 自动发现 搜索资源平台推送 + 自动发现
覆盖范围 全站历史 URL 一把梭 近 90 天活跃页,超限走 index

提交侧的补充:Google 侧 sitemap 提交后在 GSC 看状态即可,别重复提交浪费时间;百度侧把 sitemap 地址配进搜索资源平台的普通收录里,新内容页可以走 API 推送加速第一次发现。

收尾:把力气花在蜘蛛能验证的地方

60 天跑下来,有两个误区值得单独拎出来澄清。一个是"sitemap 权重调高 = 抓取变快",数据已经否掉了,priority 在 Google 是被明确忽略的字段,在百度也没观测到作用;另一个是"sitemap 写了 lastmod 就万事大吉"——lastmod 有用,前提是它真实,而且它只是让蜘蛛"知道该来",页面真被抓到还得靠内链给它铺路。这次实验里抓取量翻倍的主力,其实是第 3、4 周加的相关产品链接和面包屑,sitemap 改造只是把"告知"这一环补准了。

往后看,两个趋势顺带提一句:Google 已经宣布 2026 年 6 月后关停 sitemap ping 端点,提交越来越依赖自动发现和 GSC 主动提交,手调字段的生存空间只会更小;抓取调度的信号会持续往"可验证的事实"集中。这也是它和 GEO(Generative Engine Optimization, 生成式引擎优化)分道的地方——AI 引擎引用内容时更多看结构化数据和语义组织,传统搜索引擎的抓取索引排序链路看的还是链接与更新事实,两套优化各有各的抓手,别混为一谈。如果你的站也在纠结 sitemap 字段怎么填,欢迎把抓取统计截图发评论区,一起对对数据。

参考与延伸

SEO、sitemap、抓取预算、lastmod、changefreq、网站优化、GSC 抓取统计

🤖
本内容由 AI 辅助生成,经人工校对审核;部分素材、资料来源于公开网络,仅作个人观点分享与交流使用,无任何商业侵权意图。若内容、图片、文字涉及您的合法著作权、版权权益,请联系本人,核实后将第一时间删除、修改相关内容。