Cannibalization 的确凿证据来自 GSC:同一 query 下有两个以上 page 有曝光,且排名互相波动。脚本从 GSC 导出数据聚合出候选组,模型比对页面正文找出重叠原因,输出三种处置决策:合并(301)、差异化(改 PKW/NKW)、降权(加 noindex 或调整内链)。
AI Skill:Cannibalization 诊断——同站竞争页面识别
与注册表审计的区别
| Skill | 检查对象 | 数据来源 | 发现的问题 |
|---|---|---|---|
| 注册表审计(第45篇) | 规划层面 | registry.json | 计划中的冲突(还没发生) |
| Cannibalization 诊断(本篇) | 已发布内容 | GSC 实际数据 | 正在发生的竞争 |
注册表审计是预防,Cannibalization 诊断是治疗。已经上线的页面即使注册表配置正确,也可能因为内容写偏而产生实际竞争。
确凿证据:GSC 的 query × page 交叉数据
判断 Cannibalization 不能靠猜。唯一可靠的证据是 GSC 的查询-页面对应关系。
Cannibalization 的三个信号(需同时满足):
- 同一 query 下有 ≥2 个 page 产生曝光
- 这些页面的平均排名都在 5–30 之间(都没排到最前,也都不是完全没戏)
- 排名在时间序列上互相波动(这周 A 页排 8,下周 B 页排 12 而 A 掉到 20)
只满足第1条不是问题——大站正常情况下一个词也会有多个页面有零星曝光。三条同时满足才是真的自相残杀。
从 GSC 导出数据
GSC → Performance → Search results → 导出
需要的维度组合:Query + Page,时间范围至少3个月。
导出的 CSV 结构:
Query,Page,Clicks,Impressions,CTR,Position
centrifugal pump manufacturer,/products/centrifugal-pumps/,45,1200,3.75%,8.2
centrifugal pump manufacturer,/about/,3,340,0.88%,14.6
Skill 说明书
# Skill:Cannibalization 诊断
## 何时使用
- 某个重要关键词排名长期停滞在第2–3页
- 定期(每季度)全站诊断
- 发现 GSC 里同一 query 有多个页面曝光
## 输入
- GSC 导出的 Query + Page CSV(必需,至少3个月数据)
- 可选:站点页面正文(用于分析重叠原因)
- 可选:registry.json(用于验证是否与规划一致)
## 执行步骤
### Step 1:运行确定性脚本
执行 `scripts/cannibalization-detect.mjs`,获得候选冲突组。
脚本只做聚合和阈值筛选,不做判断。
### Step 2:逐组分析(你来判断)
对每个候选组,按以下顺序判断:
**判断 A:是否真的是 Cannibalization**
排除以下假阳性:
- 主页面排名稳定在 Top 3,另一页面只有零星曝光 → 不是问题
- 两个页面的意图确实不同(一个 commercial 一个 informational),
Google 只是暂时分辨不清 → 观察,不急处理
- 其中一个页面是分页(/page/2/)或筛选页 → 技术问题,不是内容竞争
**判断 B:确认竞争原因(需读页面正文)**
读两个页面的 H1、H2 和前 500 字,找出重叠:
- 两个页面的 H1 是否含同一核心词
- 弱势页面是否在正文大量使用了强势页面的 PKW
- 弱势页面的 NKW 是否遗漏了强势页面的 PKW
**判断 C:给出处置决策(三选一)**
| 决策 | 适用条件 | 具体动作 |
|------|----------|----------|
| 合并 | 两页内容高度重叠,业务上没必要都存在 | 弱势页 301 → 强势页,合并有价值的内容段落 |
| 差异化 | 两页都有存在价值,只是意图写偏 | 修改弱势页的 PKW 和 H1,NKW 加入强势页 PKW,重写偏离的段落 |
| 降权 | 弱势页必须存在(如 About 页)但不该排这个词 | NKW 加入该词,从正文移除该词的高频出现,减少指向它的内链锚文本 |
### Step 3:输出报告
## 输出格式
Cannibalization 诊断报告
数据区间:[YYYY-MM-DD] 至 [YYYY-MM-DD] 检出候选组:[N] 确认冲突:[N] 假阳性排除:[N]
确认冲突(按业务影响排序)
C1. query: centrifugal pump manufacturer
月曝光合计:1,540 当前最佳排名:8.2
| 页面 | 曝光 | 点击 | 平均排名 | 排名波动 |
|---|---|---|---|---|
| /products/centrifugal-pumps/ | 1,200 | 45 | 8.2 | 6–14 |
| /about/ | 340 | 3 | 14.6 | 11–22 |
竞争原因: /about/ 页面正文出现 “centrifugal pump manufacturer” 5 次, H2 使用了 “Leading Centrifugal Pump Manufacturer Since 2003”, 且注册表中 /about/ 的 NKW 未包含该词。
处置决策:降权 具体动作:
- /about/ 的 H2 改为 “Our Company History Since 2003”
- 正文中该词的出现从 5 次减到 1 次(仅在必要处保留)
- 注册表 /about/ 行的 NKW 加入
centrifugal pump manufacturer, centrifugal pump supplier - 检查全站指向 /about/ 的内链锚文本, 把含该词的锚文本改为 “about us” 或 “our company”
预期效果:/products/centrifugal-pumps/ 排名从 8.2 提升到 5 以内
假阳性排除([N] 项)
F1. query: industrial pump specifications
- /products/cp-100/(排名 4.1,曝光 800)
- /products/cp-200/(排名 18.3,曝光 45)
- 排除原因:CP-100 排名稳定 Top 5,CP-200 曝光量极低(5%), 属于正常的品牌内多型号覆盖,非竞争
## 禁止行为
- 不要在没有 GSC 数据的情况下"推测"Cannibalization
- 不要对假阳性给处置动作
- 不要建议直接删除页面(用 301 或 noindex,保留权重)
确定性脚本
// scripts/cannibalization-detect.mjs
import fs from 'fs/promises';
import { parse } from 'csv-parse/sync';
const csv = await fs.readFile('gsc-query-page.csv', 'utf8');
const rows = parse(csv, { columns: true, skip_empty_lines: true });
// 按 query 聚合
const byQuery = new Map();
for (const row of rows) {
const query = row.Query;
if (!byQuery.has(query)) byQuery.set(query, []);
byQuery.get(query).push({
page: row.Page,
clicks: Number(row.Clicks),
impressions: Number(row.Impressions),
position: Number(row.Position),
});
}
// 筛选候选冲突组
const THRESHOLD = {
minPages: 2, // 至少2个页面
minImpressions: 100, // query 总曝光至少 100(过滤长尾噪音)
minPagePct: 0.10, // 次要页面曝光占比至少 10%(过滤零星曝光)
positionRange: [3, 35],// 排名在 3–35 之间(都没排到最前)
};
const candidates = [];
for (const [query, pages] of byQuery) {
if (pages.length < THRESHOLD.minPages) continue;
const totalImpressions = pages.reduce((s, p) => s + p.impressions, 0);
if (totalImpressions < THRESHOLD.minImpressions) continue;
// 按曝光排序
pages.sort((a, b) => b.impressions - a.impressions);
// 次要页面的曝光占比
const secondary = pages[1];
const secondaryPct = secondary.impressions / totalImpressions;
if (secondaryPct < THRESHOLD.minPagePct) continue;
// 所有页面排名都在指定区间内
const inRange = pages.every(p =>
p.position >= THRESHOLD.positionRange[0] &&
p.position <= THRESHOLD.positionRange[1]
);
if (!inRange) continue;
candidates.push({
query,
totalImpressions,
totalClicks: pages.reduce((s, p) => s + p.clicks, 0),
bestPosition: Math.min(...pages.map(p => p.position)),
pages: pages.map(p => ({
...p,
impressionShare: (p.impressions / totalImpressions * 100).toFixed(1) + '%',
})),
});
}
// 按业务影响排序(总曝光量)
candidates.sort((a, b) => b.totalImpressions - a.totalImpressions);
console.log(JSON.stringify({
summary: {
totalQueries: byQuery.size,
candidateGroups: candidates.length,
thresholds: THRESHOLD,
},
candidates,
}, null, 2));
阈值调整说明
脚本里的阈值是起点,需要按站点规模调整:
| 参数 | 小站(<100页) | 中站(100–1000页) | 说明 |
|---|---|---|---|
| minImpressions | 50 | 200 | 曝光门槛,过滤噪音 |
| minPagePct | 15% | 10% | 次要页面占比门槛 |
| positionRange | [3, 30] | [3, 40] | 大站长尾词排名分布更广 |
调整原则:先用宽松阈值跑一遍,看候选组数量。如果超过20组,说明阈值太松(人工处理不完),收紧;如果少于3组,可能太严,放宽。
处置后的验证
修复不是终点,要验证效果:
修复后的验证节奏:
- 第 1 周:确认技术改动生效(301 是否正确、noindex 是否生效)
- 第 2–4 周:GSC 观察 query 下的页面数是否减少
- 第 4–8 周:观察主页面排名是否提升
- 8 周后仍无改善 → 原因可能不是 Cannibalization,重新诊断
→ AI Skill:Pillar-Cluster 内链流审计——权重流动是否形成闭环
RELATED / 相关推荐
接着读这些
按同一分类、系列与标签为你挑选。
AI Skill:注册表审计——关键词抢词与归属冲突检测
把注册表的唯一性约束检查固化成一个可复用 Skill:确定性脚本负责扫描注册表和页面内容,模型负责判断语义级抢词和给出合并建议,中间用一份写清判定规则和输出格式的说明书连接。
GEO 审计升级:从「结构合规」到「有没有被引用」
之前那个 GEO 覆盖审计 Skill 只能查结构,查不了覆盖——因为它没有期望值可比。补上意图注册表之后,审计从一层变三层:结构、覆盖与一致性、引用实测。其中复述块与主答块的一致性检查是纯确定性的,脚本能百分之百判定,这是升级带来的最大收益。
AI Skill:GEO 覆盖审计——多语言与 AI 可见性缺口分析
GEO 优化做了没做、做到什么程度,肉眼看不出来。这个 Skill 把第 40–44 篇的所有 GEO 规范转成可自动检查的规则:FAQ 是否自包含、参数表是否语义化、hreflang 是否双向、AI 爬虫是否被放行,并输出优先级排序的缺口清单。