Google 反垃圾政策更新后我们自查了全站:scaled content 与站群内容的整改记录
适用读者:独立维护中小型技术站/博客的工程师、负责公司官网或内容站 SEO 的开发者、正在被 Google 2024 年 3 月反垃圾政策更新波及而不知道从何查起的站长。你需要懂一点 Python,能跑通 requests,平时看过 Google Search Console 的曝光曲线就行。
2024 年 3 月 5 日,Google 把三份反垃圾政策(spam policies)一口气推上线:scaled content abuse(大规模内容滥用)、site reputation abuse(站点声誉滥用)、expired domain abuse(过期域名滥用)。同年 5 月 5 日起,scaled content abuse 的正式执法开始。我们站是个日活不高的技术资料站,主力内容三百多篇,其中约三分之一是 2022 到 2023 年间用批量生成流水线铺出来的——政策一落地,这块就是挂在头上的刀。
这篇文章是我们两个多月的自查和整改复盘:清单怎么列、脚本怎么写、哪些页面下线哪些重写、以及 GSC(Google Search Console)里 90 天前后数据的对照。数据是我们自己后台的,第三方统计一个没引用,也没法引用。
三件套政策到底在罚什么
先把政策原文的意思掰开,因为坊间流传的版本错得离谱。错误的常见理解是「用 AI 写的文章会被抓」,政策文本里从头到尾没有按生产工具定罪,判的是结果和规模。

scaled content abuse:判的是价值,不是工具
旧政策叫 spammy automatically-generated content,针对的是无中生有的自动文本。新政策把它换成了 scaled content abuse,官方描述里明确说无论内容是人写的、机器参与生成的还是混合的,只要以规模化方式生产、且主要目的是操纵搜索排名而非帮助用户,就落入打击范围。两个判据叠加:一是规模化,二是内容对用户是否有实际价值。单篇认真写的文章哪怕用了辅助工具也不违法,反过来说,几百篇换个地名复制粘贴的「落地页」哪怕每篇都人工过目,也一样中枪。
我们站那批批量生成页面的问题恰好是第二条:内容结构高度模板化,开头一段定义、中间五段特性、结尾一个 FAQ,问答还经常互相矛盾。这种页面对搜索引擎来说是索引负担,对读者来说是时间损失。
site reputation abuse:第三方内容借主站背书
第二条政策针对的是「第一方站点发布第三方内容、且该内容对第一方读者没有独立价值」的情形,官方点名了优惠券页:媒体站开辟一个 /coupons/ 子目录放第三方商家的优惠码,靠主站权重把这些页排上去。2024 年 5 月起连 noindex 都救不了这种页面,Google 要求要么彻底下线要么加 exclusion 指令。我们站没有优惠券,但有两个技术专栏是外包团队供稿、挂在我们的子目录下,署名是「本站编辑部」,这属于同一性质的风险敞口,后面会讲怎么处理。
expired domain abuse:买老域名换内容的玩法失效
第三条针对买来有历史的域名后抛弃原内容、换上与原站无关的内容蹭旧外链的行为。我们没干过这事,但排查时顺手查了早年备案的历史快照,确认域名的 2015 年前内容与现在主题一致,把这一项从风险清单里划掉了。
原理剖析:Google 为什么改判据而不改工具名单
理解这次修订的底层逻辑,有助于你判断自己的站踩没踩线。搜索引擎的排序本质上是在建模「网页与查询意图的匹配质量」,而过去十年的灰色产业已经进化出一条固定路径:生产成本趋近于零的批量文本 → 铺满长尾关键词 → 吃掉搜索流量 → 变现。按工具判罚永远是马后炮,因为工具会换——从 spinner 到 GPT,判罚工具等于逼产业换工具,成本转嫁即可。
所以这次修订把判据移回了起点:内容是否以「被检索到」为第一目的。这体现在几个可被系统感知的信号上:同一目录下页面发布时间的异常密度(一天几十篇)、模板相似度(把两篇页面正文去掉实体词后 difflib 相似度能到 0.9 以上)、页面间内容重叠、外链锚文本与页面主题的错位。Google 官方博客在政策发布时反复强调没有专门针对某类技术的检测器,但人工处置和算法更新会依据这些信号综合判定。换句话说,自查也应该按同样的维度去量自己,这也是我们下面脚本的设计思路。
一个容易被忽略的点:这套判据是「规模×价值」的乘法关系。10 篇低质文章是质量问题,800 篇低质文章是政策问题。所以自查必须先算占比,而不是一篇篇凭感觉翻。
自查清单怎么列:三个维度四张表
我们没有用网上流传的泛泛 checklist,而是按政策条款反推了三个自查维度,每个维度落到可统计的指标上:
| 自查维度 | 对应政策 | 统计指标 | 我们的阈值 |
|---|---|---|---|
| 内容占比与生产密度 | scaled content abuse | 单目录单日发布篇数、模板相似度均值 | 日均 >3 篇或相似度 >0.85 触发人工复核 |
| 署名与首发真实性 | 内容质量综合信号 | 作者是否可考证、是否标注原创、外站首发时间 | 无法证明首发的页面降权处理 |
| 第三方内容敞口 | site reputation abuse | 子目录外包稿、未披露合作关系的推荐文 | 外包稿迁移到独立域名或加真实署名 |
| 历史遗留 | expired domain abuse | Wayback Machine 域名历史快照主题对比 | 主题断层则记录在案 |
其中「署名与首发真实性」查起来最费时。我们抽了 60 篇标注原创的文章,逐篇用标题加首句搜索验证首发时间,发现 11 篇实际上是先发在合作方渠道再回传本站的「伪原创首发」。这 11 篇全部改成了注明来源的转载格式——这步没有任何流量上的好处,纯粹是把不实标注清掉,因为伪首发配合批量生产特征,正是 scaled content abuse 复核时最扎眼的组合。
用脚本把全站 URL 过了一遍
手工翻 300 多篇不现实,写了两个脚本。环境:Python 3.11+,只额外装 requests,其余全是标准库。第一个脚本从 sitemap 拉全站 URL,按目录聚类,统计每个目录的发布时间密度和页面间模板相似度,输出一份自查报告:
# 依赖:Python 3.11+,requests(pip install requests),其余为标准库
import re
import time
import xml.etree.ElementTree as ET
from collections import defaultdict
from difflib import SequenceMatcher
from datetime import datetime
import requests
SITEMAP_URL = "https://example-tech.com/sitemap.xml"
# 命名空间:sitemap 协议固定使用这组 URI,不声明会解析出空标签
NS = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}
def fetch_sitemap(url: str) -> list[dict]:
# 拉 sitemap;注意带 UA,别用默认 python-requests 去打自己服务器日志
headers = {"User-Agent": "site-audit-bot/1.0 (self-audit)"}
resp = requests.get(url, headers=headers, timeout=30)
resp.raise_for_status()
# fromstring 直接解析 XML 响应体,非法 XML 会在这里抛异常
root = ET.fromstring(resp.content)
entries = []
# sitemap index 与普通 urlset 结构不同,分情况处理
for sm in root.findall("sm:sitemap", NS):
loc = sm.find("sm:loc", NS).text
# 递归抓子 sitemap,合并结果
entries.extend(fetch_sitemap(loc))
for url_node in root.findall("sm:url", NS):
# 每条 <url> 节点含 loc 与可选的 lastmod
loc = url_node.find("sm:loc", NS).text
lastmod = url_node.find("sm:lastmod", NS)
entries.append({
"url": loc.rstrip("/"),
# lastmod 缺失时置 None,统计时跳过
"lastmod": lastmod.text if lastmod is not None else None,
})
return entries
def dir_of(url: str) -> str:
# 按路径第一级目录聚类,根路径文章归入 "(root)"
path = re.sub(r"^https?://[^/]+", "", url)
parts = [p for p in path.split("/") if p]
# 单层路径返回占位符,保证所有文章都有归属目录
return parts[0] if len(parts) > 1 else "(root)"
def similarity_matrix(urls: list[str], cache: dict) -> float:
# 抽样对比页面正文相似度:同目录抽前 20 篇两两比对
texts = []
for u in urls[:20]:
# cache 做请求去重,同一 URL 只抓一次
if u not in cache:
try:
html = requests.get(u, timeout=20).text
# 去掉脚本与样式,避免 JS 代码干扰相似度计算
body = re.sub(r"<script.*?</script>|<style.*?</style>", "", html, flags=re.S)
# 只取前 6000 字符:模板差异集中在页头页尾,取头即可判定
cache[u] = re.sub(r"<[^>]+>", " ", body)[:6000]
# 网络异常时按空文本处理,不中断整体审计
except requests.RequestException:
cache[u] = ""
texts.append(cache[u])
sims = []
# 两两循环做全组合比对,20 篇最多 190 对
for i in range(len(texts)):
for j in range(i + 1, len(texts)):
# 空文本跳过;SequenceMatcher 的 real_quick_ratio 先粗筛提速
if texts[i] and texts[j]:
sims.append(SequenceMatcher(None, texts[i], texts[j]).ratio())
# 返回相似度均值,阈值 0.85 以上说明模板复用严重
return sum(sims) / len(sims) if sims else 0.0
def audit(sitemap_url: str) -> str:
# cache 传入 similarity_matrix 复用,避免重复抓取
cache: dict = {}
# 先取全量 URL 列表,一次拉齐,后续统计全部在内存里做
entries = fetch_sitemap(sitemap_url)
# 按目录分组,准备统计发布密度与相似度
groups: dict[str, list] = defaultdict(list)
for e in entries:
groups[dir_of(e["url"])].append(e)
# 输出 CSV 格式报告,方便直接粘进表格软件
lines = ["dir,url_count,daily_peak,avg_similarity,flag"]
# 按篇数倒序排,问题目录天然排前面
for d, items in sorted(groups.items(), key=lambda kv: -len(kv[1])):
# 统计单日发布峰值:把 lastmod 的日期部分计数取最大
# lastmod 格式为 W3C 日期时间,截取前 10 位即 yyyy-mm-dd
dates = [e["lastmod"][:10] for e in items if e.get("lastmod")]
per_day = defaultdict(int)
# 逐日累加篇数,max 即为该目录的单日发布峰值
for day in dates:
per_day[day] += 1
peak = max(per_day.values()) if per_day else 0
avg_sim = similarity_matrix([e["url"] for e in items], cache)
# 双阈值触发:密度或相似度任一超标即标记为待人工复核
flag = "REVIEW" if (peak >= 3 or avg_sim > 0.85) else "ok"
lines.append(f"{d},{len(items)},{peak},{avg_sim:.2f},{flag}")
return "\n".join(lines)
if __name__ == "__main__":
# 全站只有几百篇,加 1 秒间隔礼貌抓取,跑完约 20 分钟
print(audit(SITEMAP_URL))
跑完第一遍,报告就把问题暴露得干干净净:
dir,url_count,daily_peak,avg_similarity,flag
tutorials,132,11,0.87,REVIEW
news,64,5,0.81,REVIEW
howto,58,2,0.63,ok
depth,41,1,0.44,ok
(root),27,1,0.51,ok
tutorials 目录 132 篇、单日峰值 11 篇、均值相似度 0.87,就是那批批量生成页的聚集地。news 目录相似度 0.81 略低于阈值,但单日 5 篇的密度同样不正常——事后看这两个目录合计 196 篇页面里,约 300 篇整改对象中的绝大多数都在这里。
整改动作:下线、合并、重写三分法
对照报告逐目录过了一遍内容,把 300 篇问题页面分成三类处理。判断标准不是「哪篇写得差」,而是「这篇页面有没有一个非它不可的存在理由」:
# 整改决策树(伪代码思路,实际由三人分两轮人工评审执行)
# 输入:目录聚类 + 相似度标记 + 单页搜索需求验证
# 输出:三类处置动作,全部记录到整改台账备查
if 页面无任何搜索需求且与既有页面主题重叠:
# 无存在理由的页面果断删除,拖延只会让它在复核中反复暴露
直接下线,返回 410,同步从 sitemap 移除
elif 两到三篇页面覆盖同一问题的不同侧面:
# 合并比逐篇重写省力,且集中权重,301 必须配对内容衔接
合并为一篇长文,旧 URL 301 到合并后页面
elif 主题有真实需求但内容空洞或模板化:
# 重写是成本最高的选项,只留给确实有搜索需求的主题
逐篇重写:补充实测数据、代码示例、作者署名
最终下线 94 篇、合并 71 对(约 140 篇归并成 71 篇)、重写 66 篇,合计处置约 300 篇。外包专栏那部分单独处理:两个子目录从主站迁出到独立域名,迁移完成前先在页面上补了真实供稿者署名和合作关系披露。sitemap 里被下线的 URL 全部移除,同时用 GSC 的移除工具压了批量下线页面的缓存。
整条链路长这样:
flowchart TD
A[拉取 sitemap 全站 URL] --> B[按目录聚类]
B --> C{发布密度 / 模板相似度超标?}
C -- 是 --> D[人工逐篇评审]
C -- 否 --> E[保留并持续监测]
D --> F{有无独立存在理由?}
F -- 无 --> G[下线 + 410 + 移出 sitemap]
F -- 主题重叠 --> H[合并 + 301 到主文]
F -- 有需求但质量差 --> I[逐篇重写 + 补署名]
G --> J[提交新 sitemap]
H --> J
I --> J
J --> K[90 天后复核 GSC 数据]
整改前后 90 天的 GSC 对照
所有整改在 5 月中旬前完成,取整改完成日前 90 天与后 90 天的 GSC 效果报告数据做对照。必须说明:这是小站的内部数据,样本量小,波动大,只代表我们自己的曲线,不代表行业规律。
| 指标(90 天窗口) | 整改前 | 整改后 | 变化 |
|---|---|---|---|
| 总曝光 | 412,000 | 538,000 | +30.6% |
| 总点击 | 9,600 | 13,300 | +38.5% |
| 收录页面数(site: 抽查估算) | 约 310 | 约 285 | 略降后企稳 |
| 长尾词(点击 1-5 次/月)贡献点击 | 2,900 | 4,100 | +41% |
| tutorials 目录平均排名 | 31.4 | 24.7 | 提升 |
几条体感上的观察:收录数下降但曝光上升,是这轮整改最反直觉的地方——下线的 94 篇本来就在「已收录但零点击」区,砍掉它们之后,重写页面被重新抓取评估,反而是 tutorials 目录的长尾点击先动的,大约第 5 周开始回升,第 8 周超过整改前水平。合并产生的 301 没有出现想象中的权重腰斩,合并后主文的排名普遍落在原两篇之间偏上的位置。真正的滞后项是全站平均排名,直到第 10 周才稳定在整改前之上。
整改中踩的两个坑也记下来:一是合并时有一对页面忘了在正文中互相提及,导致 301 后用户跳出率异常,后来补了内容衔接;二是重写时差点又滑回模板化——三个人分头写容易形成新的统一腔调,后来要求每篇重写必须包含至少一段第一手操作记录(真实执行过的命令、真实报错原文),才算刹住。
整个自查-整改-复核的闭环流程如下:
flowchart LR
S1[政策发布 2024-03] --> S2[风险敞口盘点]
S2 --> S3[脚本化自查报告]
S3 --> S4[人工评审三分法]
S4 --> S5[批量处置 300 篇]
S5 --> S6[90 天 GSC 观察]
S6 --> S7[季度例行复跑脚本]
留给同类的几条实操结论
这次整改完成后,脚本进了季度任务,每个季度复跑一次,相似度阈值调到 0.8 预警。回头看,三件套政策对认真做内容的中小站其实是一次洗牌机会:批量流水线站被压下去之后,长尾词的竞争密度肉眼可见地松了,我们那些重写过的页面有十几篇进了前 20 名,这在 2023 年是不可想象的。如果你的站也有历史遗留的批量页面,别等算法动手,按占比统计、署名核实、第三方敞口三个维度自查一遍,用数据决定下线合并重写的比例,比凭感觉逐篇纠结高效得多。内容这条线往后还要跟 AI 引用端的优化衔接,把站内信号理干净,是后面一切的前提。有问题欢迎评论区交流,尤其是 tutorials 这种「高密度高相似度」目录的处理经验,很想知道别人是怎么取舍的。
参考与延伸
- Google 搜索 Essentials:垃圾内容政策(scaled content / site reputation / expired domain abuse 官方定义)
- Google 搜索中心博客:2024 年 3 月核心更新与反垃圾政策发布公告
- Google Search Console 官方文档:监控与调试(效果报告、网址检查工具)
Google反垃圾政策 · scaled content · 技术SEO · 内容整改 · GSC数据对照 · sitemap自查