大量页面 meta description 重复:怎么修

爬虫报告几百页共用同一句 meta description。没有排名惩罚,但悄悄吃掉你的点击。这是定向修法,不用花一个周末重写全站。

Screaming Frog 或 Ahrefs 报”247 页 meta description 重复”,你想花一个周末把这 247 页全重写。别。重复 meta description 没有排名惩罚,Google 到 2026 年也反复说过这点。它真正让你付的代价是点击率:snippet 长得一模一样,搜索结果看起来雷同,用户就直接划过去了。

最快修法: 按曝光量(不是按重复次数)挑出流量前 50 左右的页,把这些页的 description 改写成独特、具体的摘要。长尾页要么用每页自己的元数据自动生成 description,要么干脆删掉 <meta name="description"> 标签,让 Google 按 query 自己合成 snippet。一句又弱又重复的 description,比没有还糟。

动手前先澄清一点:以前 Search Console 里那个会标这个问题的 HTML Improvements 报告,Google 几年前(2018 年)就下线了。如果你是在那里看到的标记,那是缓存里的老数据。截至 2026 年 6 月,活的信号来自第三方爬虫(Screaming Frog、Ahrefs、Sitebliss、Semrush),不是 Search Console。

先判断你属于哪一类

跑一次爬虫,再把现象对到原因上。按”实际是哪条”的命中率从高到低排。

爬虫里的现象最可能的原因对应小节
一堆不相关的页一字不差共用站点标语模板 fallback 到站点级 description原因 1
重复都集中在作者留空的页CMS 有字段但不是必填原因 2
只有 /category//tag//archive/ 页重复列表页模板通用原因 3
/page/2//page/3/ 跟父页一致分页继承父页 description原因 4
description 都用同样的前 3-4 个词开头自动取正文前 155 字符原因 5
重复成对出现(EN/ZH 等语言对)翻译没覆盖 meta 字段原因 6

常见原因

1. 模板 fallback 到站点级 description

const description = article.description || site.description;

article.description 为空时,吐的是站点标语。所有没显式填 description 的文章都拿到同一句话。

怎么判断: 统计有多少 HTML description 等于你的站点标语。超过 20 页共用,就是这条。

2. CMS 字段从未逐篇填

CMS 里有 meta description 字段但不是必填。作者留空,模板 fallback(原因 1)兜底。

怎么判断: 审你文章的 description frontmatter,统计有多少是空或模板默认值。

3. 自动生成的分类 / 标签 / 归档页

/category/ai-tools//category/productivity//category/tools/ 都用了通用模板,比如 “Browse our latest articles on this topic.”

怎么判断: 随便读 5 个列表页的 meta description。通用且一样,就是模板的问题。

4. 分页页共用父页 description

/blog/page/2//blog/page/3/ 等都继承了 /blog/ 的 description。这些页通常本来就不该被收录。

怎么判断:

curl -s https://yoursite.com/blog/page/2/ | grep -oP 'name="description" content="\K[^"]+'

输出跟 /blog/ 的 description 一致,就是这条。

5. 自动取正文前 155 字符

模板”聪明”地取文章正文前 155 字符当 description。文章如果都用同样的样板开头(“在本文中我们将……”),每条 description 就都变成近重复。

怎么判断: 对比 5 篇文章的 description。都用同样的前 3-4 个词开头,就是自动提取太激进。

6. 翻译页共用源语言 description

EN 和 ZH 版本共用 EN description,因为翻译那一步根本没碰 meta 字段。文章越多,每篇就多产生一对重复。

怎么判断: 对比 /en/<article>.mdx/zh/<article>.mdxdescription frontmatter。一样就是翻译跳过了 meta。

最短修复路径

第 1 步:导出重复 map

# 从 sitemap 拉每个 URL 的 description,再按重复分组
curl -s https://yoursite.com/sitemap.xml | grep -oP '<loc>\K[^<]+' | \
while read url; do
  desc=$(curl -s "$url" | grep -oP 'name="description" content="\K[^"]+')
  printf '%s\t%s\n' "$desc" "$url"
done | sort | uniq -c -d -f1 -w200 | sort -rn | head -50

这会把重复分组,并按次数降序排。最上面几行就是最该先动的目标。(站点大的话,直接用 Screaming Frog 之类的爬虫更快,而且会帮你遵守 robots.txt 和 crawl-delay。)

第 2 步:按流量优先,不按次数

把重复 URL 跟 Search Console -> Performance -> Search results -> Pages(按曝光排序)对照。聚焦交集:既重复、又有真实曝光的页。

这通常是 50-200 页,而不是全部 247 页。这些先给独特 description。长尾可以等,或者第 4 步交给程序化生成。

第 3 步:为头部页写独特 description

每页按这个结构:

[主关键词短语] + [独特数字 / 细节] + [用户价值]
差(模板默认)
”AI 效率指南——最新工具与技巧""2026 我付费用的 12 个 AI 工具,外加用一周就弃掉的 8 个"
"浏览我们的分类页""47 篇 Astro on Vercel 实战排错指南”

英文大致 110-160 字符(中日韩约 50-80 字)。Google 说没有硬性长度上限,但会把展示的 snippet 截断以适配设备宽度,所以手机上能稳定展示的是前约 110-120 字符。把最有辨识度的部分放前面。

第 4 步:长尾从元数据生成

Google 明确说,对大型、数据库驱动的站点,程序化生成 description 是”appropriate and encouraged”(合适且鼓励的),前提是”human-readable and diverse”(可读且有差异)。用每页自己的数据拼字符串,让它天然唯一:

function generateDescription(article) {
  const intro = article.firstParagraph?.slice(0, 100)?.trim();
  const stats = `${article.wordCount} words · ${article.readTime} min read · ${article.tags.join(", ")}`;
  return `${intro} — ${stats}`.slice(0, 160);
}

坑在这:别只是一字不差地截正文前 155 字符(原因 5)。要带入页面专属数据——标签、计数、H1、某个关键数字——这样两篇开头相似的文章也会产出不同的 description。

第 5 步:或者长尾干脆省略 meta

写不出独特、有力 description 的页,就一个都别写。Google 会按 query 合成 snippet,对很具体的 query 来说,这常常比一句弱的模板描述更好。

{article.description && (
  <meta name="description" content={article.description} />
)}

没有 description 标签,胜过一句重复且弱的。

第 6 步:CMS 里把 description 设为新内容必填

在 Astro content collection(src/content/config.ts)里:

const article = z.object({
  title: z.string(),
  description: z.string().min(50).max(160),  // 必填,带长度边界
  // ...
});

这样任何新文章在 description 不达标时都构建不过,问题在你清理存量时不会继续变大。

第 7 步:CI 加去重校验

// scripts/check-description-uniqueness.mjs
import fs from 'node:fs';
import matter from 'gray-matter';

const seen = new Map();
const issues = [];

for (const file of fs.readdirSync('src/content/articles/en')) {
  const { data } = matter(fs.readFileSync(`src/content/articles/en/${file}`, 'utf8'));
  const desc = data.description?.trim();
  if (desc && seen.has(desc)) {
    issues.push(`DUPE: ${file} == ${seen.get(desc)}`);
  } else if (desc) {
    seen.set(desc, file);
  }
}

if (issues.length) { console.error(issues.join('\n')); process.exit(1); }

把它接进 prebuild,重复 description 在上线前就让构建失败。

第 8 步:重交 sitemap 后等

在 Search Console 重交 sitemap,或者干脆等下一次爬虫抓到改动。实时结果里的 snippet 会在接下来 1-4 周随 Google 重新抓取而更新;全站没有”请求重抓”的按钮,但你可以对最有价值的几页用 URL Inspection -> Request indexing 来加速。

怎么确认修好了

  1. 重跑同一个爬虫。 重复 description 数应该降到只剩你有意保留为程序化生成或留空的那些长尾页。
  2. 抽查实时 snippet。site:yoursite.com "改写后的原句",确认显示的是新 description(或按 query 合成的版本),不是旧标语。给一两周重抓时间。
  3. 看 Search Console 的 CTR。 把改写过的页在改动后 28 天的平均 CTR 跟改动前对比。改对了的,这些 URL 的 CTR 通常会抬升。
  4. 确认拦截生效。 试着提交一篇 description 留空或重复的文章,CI(第 6-7 步)应该拒掉它。

哪些情况不是你操作错了

Google 有相当大比例的情况会按 query 自己生成 snippet。你的 meta description 只是它在 query 大体匹配页面时回落用的”默认值”。对很具体的 query,不管你写了什么,Google 合成的 snippet 通常都会赢——所以即便某些搜索下改写过的页还是显示 Google 生成的 snippet,也别慌。那是预期行为,不是修复失败。

预防建议

  • 在 schema 里把 description 设为必填、带长度边界(Zod 或等价方案)。
  • 模板 fallback 留空,不要写死一句标语,免得缺失的 description 静默变成重复。
  • 构建期跑 CI 去重校验,重复就 fail。
  • 分类 / 标签 / 分页页:每页写独特引言,或者 noindex 掉。
  • 每季度用爬虫审重复 description 的比例;超过可收录页的约 10% 就重写。

FAQ

  • 重复 meta description 会伤排名吗? 不会。Google 已确认重复(或缺失)meta description 没有排名惩罚。代价是点击率,不是排名位置。
  • 多少重复算太多? Google 没有强制阈值。实务上:高曝光页哪怕一个重复都值得修,因为影响 CTR;埋在长尾里的几个重复不值得花一个周末。
  • 要全部重写吗? 不用。按曝光排序优先级。高流量页手写,长尾页用程序化生成或直接删标签处理。
  • HTML Improvements 报告不是在叫我修这个吗? 那个报告 2018 年就从 Search Console 下线了。你现在还看到标记的话,是来自第三方爬虫。以那次爬虫结果为准。
  • 从正文前 155 字符自动取是个好捷径吗? 通常不是。文章共用样板开头时,你会把重复又造一遍(原因 5)。改成从页面专属元数据生成(第 4 步)。
  • Google 会忽略重复 description 吗? 经常会。Google 会改写或替换它判定为无用或重复的 description——也就是说,一句差的 description 横竖都是白费力气。只有独特、准确的那种,它才会稳定保留。

相关阅读

标签: #SEO #排查 #排查 #结构化数据 #重复 Meta