爬虫审计报「80 页 <title> 完全一样」。你一查——全是 MySite Blog、或 MySite — Tag Page、或 Article on MySite。Google 在搜索结果里分不清它们,这一整簇页面的点击率(CTR)都很差,审计工具也一直把站点亮红。
最快的修法:用爬虫导出每个 URL 和它的 <title>,按 title 排序,先攻最大的那一组重复。给每页一个独特、有描述性的 title(文章用 frontmatter 的 title:、分页加页码后缀、双语对加本地化标题)。然后加一个构建期检查——只要两个可索引页撞 title 就 fail CI,这样问题就不会卷土重来。
开始前先说清一件事:截至 2026 年 6 月,Google Search Console(GSC)里没有原生的「重复 title」报告。以前那个会列出重复和缺失 title 的 HTML Improvements 报告,早几年就被下线了。今天要找重复,只能自己爬站;要确认 Google 不满意,就看 Performance 报告里那些曝光高、CTR 低的页面。所以你手上这份审计,几乎可以肯定来自 Screaming Frog、Sitebulb、Ahrefs 或 Semrush,而不是 Google 本身。
重复 title 到底伤在哪
重复 title 会造成关键词自相蚕食(keyword cannibalization)——Google 拿不准你哪一页该排某个查询,于是这几页全都排得更差;同时它还拉垮 CTR,因为摘要看起来都一个样。它还会逼 Google 替你改标题:2025 年 Q1 的一项研究发现 Google 重写了约 76% 它见到的 title 标签(2023 年约为 61%),而且 2026 年 3 月 Google 确认正在标准搜索结果里测试 AI 生成的标题改写。当你的 title 又泛又重时,等于把改写的理由直接递给 Google。想保住你亲手写的标题,最好的办法就是让它独特、具体。
常见原因
按命中率从高到低。动手改之前先确定自己属于哪一类。
1. per-page title 缺失时套了模板 fallback
你在 frontmatter 里写了 title:,但 title 为空时模板会 fallback 到 MySite Blog——好几篇你从没填过 title 的文章,现在共用这个 fallback 字符串。
如何判断:每个带 fallback 标题的页面,frontmatter 里 title: 都是空的或缺失。用这条命令列出来:
grep -rL "^title:" src/content/articles --include="*.mdx"
2. 分页(Page 2、Page 3)共用了父页标题
/blog/ 是 MySite Blog,/blog/page/2/ 也是 MySite Blog,/blog/page/3/ 还是。分页改了 URL,却没改 title。
如何判断:URL 形如 /page/N/ 或 ?page=N,但 <title> 一模一样——URL 在区分,title 没有。
3. 双语页没带 locale 标记
/en/articles/topic/ 和 /zh/articles/topic/ 都输出 <title>Topic</title>。尽管 URL 不同,Google 仍可能把它们去重——尤其在 hreflang 标注缺失或不匹配时。
如何判断:同一个 translationKey 对、title 一致。ZH 版本应该带中文字;如果两边都读 Topic,说明模板根本没本地化标题。
4. 自动生成的 tag / 归档页
50 个 tag 页都叫 Tagged: ${tagName}——但模板只输出了 Tagged: 没替换变量,于是每页字面上就是 <title>Tagged: </title>。
如何判断:一连串页面的 <title> 里有格式字符串残片,说明模板变量插值失败了。
5. CMS 或 bulk-edit 把多个 title 合成了一个
一次查找替换或 normalize 脚本覆盖了多个文件的 title:,它们现在共用一个模板派生的标题。
如何判断:找一次近期把多个 title 一起改掉的批量提交。
git log --all -p -S "title:" -- src/content/articles/
留意某一次 edit 把很多 title: 行都设成了同一个值。
6. Syndicated / import 的内容保留了原站标题
从合作博客 import 的文章保留了原 <title>,现在成了你站 50 页的 title——全和合作方的旧格式一致。
如何判断:共用的 title 可疑地带着别的站点的 branding,或带着你站从不用的日期格式。
一眼对照诊断
| 你在爬虫导出里看到的现象 | 大概率是哪一类 | 用什么修 |
|---|---|---|
共用同一 fallback 字符串、frontmatter title: 为空 | 模板 fallback(1) | title: 改必填,缺失 fail build |
/page/2/、?page=2 共用父页标题 | 分页(2) | 加 — Page 2,并给每页自指向 canonical |
同 translationKey、ZH 页无中文字 | 双语撞标题(3) | 本地化标题,核对 hreflang |
<title> 里有 ${...} 或结尾的 : | tag/归档模板 bug(4) | 修变量插值 |
| 很多标题在一次近期提交里被改 | bulk-edit 覆盖(5) | 从 git log 恢复或逐页重写 |
| 标题带着别站 branding / 奇怪日期格式 | import 内容(6) | 重写成你自己的风格 |
最短修复路径
按收益从高到低。Step 1 审计,Step 2 与 Step 6 防再发。
Step 1:爬一遍、导出、按 title 分组
# 用 Screaming Frog、Sitebulb、Ahrefs Site Audit,或自己写爬虫。
# 导出 URL + <title> 为 CSV,再按 title 分组、count 倒序。
你会看到最大的几个重复 cluster。先修最大的——把 80 页共用一个标题清掉,比追着 5 个小重复划算。
Step 2:每组决定怎么差异化
| Cluster 类型 | 修法 |
|---|---|
| 模板 fallback | title: 改必填,缺失 fail build |
| 分页 | 加 — Page 2 / — Page 3,并给每个分页页一个自指向 canonical(不要全部 canonical 到第 1 页) |
| 双语撞标题 | 本地化每种语言的标题(如 EN Topic、ZH 主题),并确认双向 hreflang |
| Tag 页格式字符串 bug | 修模板变量替换 |
| bulk-edit 覆盖 | 从 git log 恢复或逐页重写 |
| import 的 syndicated 内容 | 重写 title 符合你站风格 |
关于分页再补一句:Google 早在 2019 年就不再用 rel="prev" / rel="next" 做索引,而是把分页页当普通页处理。所以让 /page/2/ 区分开的,只有独特的 title 和一个自指向 canonical。把每个分页页的 canonical 都指向第 1 页,等于告诉 Google 忽略第 2 页之后的所有页——通常这正好和你想要的相反。
Step 3:title 既要独特,也要可搜、能扛得住改写
光独特还不够,还得可搜索、并且扛得住 Google 的改写。加具体信息,长度大致保持在 30 到 60 字符(Google 最常原样保留的区间),并把最能区分的词放前面。品牌名经常被 Google 从标题里删掉,所以品牌要放就放结尾。
差:「Article」 (独特但没用)
好:「Claude API streaming responses, step by step (2026)」
靠 specificity(具体)来差异化,而不是加数字或加 v2。
Step 4:重提 sitemap + 申请重索引
标题改完后:
# Astro 和多数静态生成器会在 build 时重建 sitemap。
pnpm build
然后在 Google Search Console:Sitemaps -> 重新提交 sitemap URL。对个别高流量页面,用 URL Inspection -> Request Indexing。Google 不重爬就看不到新标题,显式提交能加速。SERP 摘要刷新一般要几天到两周。
Step 5:实在去不掉的重复,用 noindex 或 canonical
有些重复是合法的——/login、/404、几乎一样的 /about 类页面、打印版变体。对那些你根本不想被收录的页,加 noindex robots meta。对两个确实内容相同的 URL(比如带跟踪参数的变体),选一个保留,给重复那个加 rel="canonical" 指向保留页。把「唯一 title 规则」留给可索引、有自然流量潜力的页。
Step 6:加 CI 断言,让它无法复发
// scripts/check-unique-titles.mjs
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";
const seen = new Map();
const issues = [];
function walk(dir) {
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
if (fs.statSync(p).isDirectory()) walk(p);
else if (p.endsWith(".mdx") || p.endsWith(".md")) {
const { data } = matter(fs.readFileSync(p, "utf8"));
if (data.draft) continue;
const title = (data.title || "").trim();
if (!title) { issues.push(`MISSING TITLE: ${p}`); continue; }
// 直接按 title 比对;en/ 和 zh/ 的标题本就该不同,
// 只有当两者逐字节相同(真正的双语撞标题)才会触发。
if (seen.has(title)) issues.push(`DUPLICATE: ${p} == ${seen.get(title)}`);
else seen.set(title, p);
}
}
}
walk("src/content/articles");
if (issues.length) {
console.error(issues.join("\n"));
process.exit(1);
}
接到 prebuild 上。这样重复 title 和缺失 title 都会在上线前 fail CI。
如何确认已修好
- 重跑爬虫、重新导出 URL +
<title>。最大的那组重复,每个 title 的 count 应降到 1(或只剩合法的noindex页)。 - 本地跑
node scripts/check-unique-titles.mjs,应以 0 退出。 - 在 Search Console 对修好的页用 URL Inspection,点 View crawled page,看 Google 上次抓到的
<title>。重爬之后应显示新标题;若还是旧的,再申请一次索引并等待。 - 一两周后,看这些页在 Performance 报告里的表现——随着摘要刷新,原来撞标题那一簇的 CTR 应开始回升。
预防建议
- per-page title 必填;没填就 fail build(不要静默的模板 fallback)。
- CI 断言:没有两个可索引页共用同一个
<title>。 - 分页 / 语言 / tag 模板按构造就输出独特 title。
- 季度爬一遍 + 审一遍,揪出 import 或迁移内容产生的新重复。
- bulk-edit 脚本必须保留 per-page title;要重写就 log 下来并 review。
- 靠 specificity(具体描述)差异化,而不是 append
v2。
常见问题
Google 会因为重复 title 而惩罚我吗? 没有专门针对「重复 title」的惩罚,但影响是实打实的:重复 title 造成关键词自相蚕食、拉低 CTR,还会让 Google 更倾向用自己(2026 年起常是 AI 生成的)文本替换你的标题。损失的是排名和点击,而不是 manual action。
2026 年 Search Console 在哪看重复 title? 没有直接的地方。以前列出它们的 HTML Improvements 报告已下线。用爬虫(Screaming Frog、Sitebulb、Ahrefs、Semrush)找重复,再用 GSC 的 Performance 报告——曝光高、CTR 低——找出摘要表现不佳的页。
分页页的标题重复算问题吗?
算。Google 现在把 /page/2/ 当普通页处理(rel="prev"/rel="next" 自 2019 年起被忽略),所以每个分页页都需要独特的 title 和一个自指向 canonical。加 — Page N 是最省事的修法。
英文版和中文版可以共用一个标题吗?
不行——给每种语言一个本地语言的标题,并用双向 hreflang 配对。如果两边都读 Topic,Google 可能把它们合并、只挑一个展示,白白浪费另一种语言的覆盖面。
改完多久 Google 才会显示新标题? 改好标题并申请索引后,SERP 摘要刷新一般要几天到约两周,取决于 Google 抓取该页的频率。