标签页太多拖累 SEO?别急着用 robots.txt 屏蔽

前阵子折腾完 llms.txt,又顺手盯上了博客的 SEO。起因是我数了一下标签:35 篇文章,居然攒出了 69 个标签,其中将近一半(49 个)只挂着孤零零一篇文章——JWTMonacoNext.jsmanim……这些 /tags/xxx 页面,内容基本就是把那一篇文章又列了一遍,是典型的「薄内容」(thin content)。

我的第一反应跟很多人一样:在 robots.txtDisallow: /tags/,让搜索引擎别去爬这些垃圾 URL,省得它们污染索引。动手之前查了一圈,发现这个直觉是错的——准确说,是「用错了工具」。记一下这个坑,以及最后实际怎么改的。

robots.txt 到底管什么

这是最容易搞混的一点:robots.txtDisallow 管的是「爬不爬」,不是「收不收录」。

这两件事是分开的。Disallow 只是告诉爬虫「这个路径你别进去抓」,但它管不住「收录」。只要别的地方有链接指向 /tags/JWT/,Google 照样可以把这个 URL 收进索引——只不过因为它被禁止抓取,没法读到页面内容,于是就在搜索结果里显示成一条没有标题、没有摘要的「裸 URL」。这种条目比薄内容还难看。

更要命的是第二层:一旦 Disallow,你就把自己的后路也堵死了。 假设你后来想把这些页面彻底从索引里删掉,正规做法是给页面加 noindex 标记(下面会讲)。但 noindex 写在页面的 HTML 里,爬虫得先「爬进去」才能看到它。你都 Disallow 了,爬虫进不来,自然读不到 noindex,于是这些页面就卡在一个「想删却删不掉」的尴尬状态里。

官方文档其实把这话说得很直白。Google 的 robots.txt 说明里明确写着:robots.txt 不是用来阻止网页被收录的机制,想让网页不出现在搜索结果里,应该用 noindex 或者加密码保护。

至于「省爬取预算(crawl budget)」这个最常被搬出来的理由——对一个 35 篇文章的小站来说根本不成立。Google 爬几百个 URL 毫无压力,crawl budget 是那种几十万页的大站才需要操心的事。所以用 Disallow 来解决我这个问题,是个三输的选择:删不干净、留裸 URL、还顺便切断了标签页向正文传递的内链权重。

正确的工具:noindex, follow

真正该用的,是写在页面 <head> 里的这一行:

<meta name="robots" content="noindex, follow">

拆开看这两个词:

  • noindex——告诉搜索引擎「这个页面别收录」。这才是直接、明确地把薄页面踢出索引的开关。
  • follow——「但页面里的链接你还是要顺着爬」。标签页本身不值得收录,可它列着一堆通往正文文章的链接,这些链接得留着,让爬虫顺藤摸瓜爬到真正有价值的文章,内链权重也能正常传递。

注意这里有个关键前提,跟上一节正好呼应:robots.txt 必须保持全开,Google 才爬得进来、读得到这条 noindex 所以「Disallow + noindex」是自相矛盾的组合,千万别同时上。两条路的区别我画了张图:

左边 robots.txt 用 Disallow 屏蔽 tags 目录:Googlebot 被挡在门外,读不到页面,结果是有外链时仍被收录成没有摘要的裸 URL、读不到页内 noindex 想删也删不掉、内链权重也传不到正文;右边用 meta robots 的 noindex follow:Googlebot 正常进入页面读到标记,结果是这个标签页不进索引、follow 让爬虫顺藤摸到正文、正文照常收录权重不丢。底部强调前提是 robots.txt 保持全开,Google 才读得到 noindex

在 Astro 里怎么改

这个博客所有页面的 <head> 都走同一个 BaseHead.astro 组件,所以加个开关很简单。先给它一个 noindex 属性:

interface Props {
  // ...原有字段
  /** 给标签、分类这类薄页面用:不进索引,但仍让爬虫顺着链接爬到正文 */
  noindex?: boolean;
}

const { /* ...其他 */ noindex } = Astro.props;

然后在合适的位置条件渲染那行 meta:

<link rel="canonical" href={canonicalURL} />

{noindex && <meta name="robots" content="noindex, follow" />}

剩下就是在四个 taxonomy 页面上把这个开关打开——标签列表页、单个标签页、分类列表页、单个分类页:

<!-- src/pages/tags/[tag].astro 等四个文件 -->
<BaseHead title={`Tag: ${tag} · ${SITE_TITLE}`} description={SITE_DESCRIPTION} noindex />

正文文章页和首页完全不动,照常被收录。改完 pnpm build,去 dist/ 里抓一下生成的 HTML 验证:标签页、分类页都带上了 noindex, follow,而博客正文页里搜不到 robots 这个 meta——符合预期。

别忘了 sitemap 这条腿

noindex 只是三件套里的一件。我之前其实已经在 astro.config.mjs 的 sitemap 配置里,把 /tags/categories 过滤掉了:

sitemap({
  filter: (page) =>
    !/\/(tags|categories)(\/|$)/.test(new URL(page).pathname),
}),

把这几样配合起来看,逻辑才完整:

  • 不主动提交——sitemap 里不放它们,等于不向 Google 推荐;
  • 不收录——页面上的 noindex 把它们挡在索引外;
  • 但允许爬——robots.txt 全开 + follow,保证爬虫能进来读到 noindex,也能顺着链接爬到正文。

三条缺一不可。尤其别犯那个最经典的错:既在 sitemap 排除、又在 robots.txt 里 Disallow、还指望 noindex 生效——后两个是打架的。

几点保留判断

  • 生效要等重爬。 加了 noindex 不是立刻见效。如果这些标签页之前已经被收录过,得等 Google 下次重新爬到它、读到这行标记,才会把它从索引里拿掉,这个过程通常要几天到几周。想催一下,可以去 Search Console 用「网址检查 → 请求编入索引」手动点几个。
  • 要不要全 noindex,是个取舍。 我这次是把所有标签页一刀切全 noindex 了,图省心。更精细的做法是只 noindex 那些「单篇标签」,给文章数多的标签(我这是 AIClaude CodeLinux 这几个)留着可索引——它们算是有聚合价值的主题入口,偶尔能吃到点「主题词」的流量。但那要写判断逻辑,对我这种规模收益不大,所以我选了简单的那条。你的站如果标签普遍都挂着不少文章,可能就不该全关。
  • 这事有多大用,我也不敢吹。 薄内容会不会真的拖累 SEO、noindex 之后排名会不会变好,这些我没有可量化的对照数据,纯粹是按「让索引保持干净」这个通行的最佳实践在做。官方怎么说是一回事,具体落到我这个小站有多少实际影响,自己打个折扣。我能确定的只有一点:至少别用 robots.txtDisallow,那个是实打实的反效果。

小结

  • 标签页、分类页这类「一篇文章撑一页」的薄内容,确实是索引里的噪音,值得收拾;
  • 但别用 robots.txtDisallow——它只挡爬取不挡收录,会留下删不掉的裸 URL,还切断内链权重;
  • 正确工具是页面里的 <meta name="robots" content="noindex, follow">:不收录该页,但仍顺着链接爬到正文;
  • 前提是 robots.txt 保持全开,Google 才读得到这条 noindex,所以两者不能同时上;
  • 配合 sitemap 排除,凑成「不提交 + 不收录 + 但可爬」三件套,逻辑才自洽。