How I rebuilt Astro slug pages after AdSense flagged three sites for scaled content abuse
How I rebuilt Astro slug pages after AdSense flagged three sites for scaled content abuse
三周前,我描述了 AdSense 如何拒绝了我的三个目录网站,原因在于它们部署在 *.vercel.app 子域名上。当时的修复方案很简单:添加自定义域名、设置重定向并重新提交。我照做了,域名也已上线。5 月 11 日,我收到了重新审核的结果:域名过滤通过了,但内容过滤没通过。AdSense 给出的理由是“大规模内容滥用 / 低价值内容”。这比之前的拒绝更难处理,因为它要求从根本上改变页面的运作方式,而不仅仅是调整设置。本文记录了我具体做了哪些修改,以及为什么我认为这些修改能解决过滤问题——需要说明的是,我尚未收到最终的复审决定,因此这目前只是一个待验证的假设,而非确定的修复方案。
What “scaled content abuse” actually means
什么是“大规模内容滥用”?
Google 2024 年 3 月的垃圾内容更新正式定义了文档中所称的“主要为了提升搜索排名而大规模生产(无论是通过自动化还是其他方式)的网站”。关键短语是“主要为了提升搜索排名”——规模本身并不是政策打击的目标。从审核者的角度来看,核心问题是:每个页面是否提供了用户在网站其他页面无法获得的内容?还是说它们只是替换了不同名词的结构性克隆?说实话,我的 slug 页面大多是替换了名词的结构性克隆。对于 aiappdex.com,无论模型是 70B 的大语言模型、22M 的嵌入模型,还是 1.5B 的音频分类器,每个 AI 模型页面的开头段落结构都是一样的。“我们如何看待这个模型”部分使用了完全相同的文本,只是替换了模型名称。数据列变了,但编辑口吻没变。对于 findindiegame.com,情况更糟。每个游戏页面的“关于”部分都是 Steam short_description 字段的逐字拷贝。这不是精选内容,而是带个标题的抓取内容。我在发布时就知道这有风险,但我还是发布了,因为为数百款游戏撰写原创文案并不在最初的构建计划中。现在,这个权衡付出了代价。
Why template text fails the uniqueness test
为什么模板文本无法通过唯一性测试
“让内容具有唯一性”听起来显而易见,但执行起来比看起来要难得多。模板文本失败的原因不是因为它说了假话——模板化的引言可以是准确的。它失败是因为它是可互换的。如果你能把一个页面的引言换到另一个页面,读起来依然通顺,那么这段文字就不是针对该页面特有的。这只是围绕数据进行的格式化,而不是关于数据的写作。Google 可以从结构上检测到这一点:如果两个页面在句子结构上有大量的 n-gram 重叠,而仅仅是命名实体不同,那么即使没有重复的句子,这种模式也是一个信号。网站页面越多,统计证据就越强。修复方法不是增加字数。更长的模板段落依然是模板。修复方法是让每个页面的文案依赖于数据库字段,这些字段在不同条目之间确实存在差异,从而改变了所表达内容的编辑含义。
The AI tools rewrite: pipeline type + download tier
AI 工具页面的重写:流水线类型 + 下载层级
aiappdex.com 的 slug 页面现在做了三件以前没做过的事。首先,“这适用于什么场景?”部分根据流水线类型(pipeline type)进行了分支处理。之前仅用于过滤的 HuggingFace 流水线标签现在决定了文案的生成。大语言模型页面得到的建议与嵌入模型、视觉模型页面完全不同:
const isLLM = /text-generation|conversational|chat/i.test(model.pipeline_tag ?? "");
const isEmbedding = /sentence-similarity|feature-extraction/i.test(model.pipeline_tag ?? "");
const isVision = /image|vision|object-detection|depth-estimation/i.test(model.pipeline_tag ?? "");
const isAudio = /audio|speech|whisper|tts/i.test(model.pipeline_tag ?? "");
每个分支都会生成结构上完全不同的决策路径——不是对同一建议使用不同的形容词,而是完全不同的建议。大语言模型页面讨论的是量化和 GGUF 构建的权衡;嵌入模型页面讨论的是维度和多语言训练数据;视觉模型页面讨论的是 ONNX 导出和边缘设备限制;音频模型页面讨论的是 VAD 前端和标点符号后处理。这些是不同的主题,而不是同一主题的不同说法。其次,“我们如何看待这个模型”部分根据下载层级进行分支。下载量超过一千万次的模型会获得一段关于社区知识深度和 StackOverflow 覆盖率的描述;十万到一千万次的模型会获得一段关于教程可用性与源码阅读要求的描述;一千次以下的则会获得一段关于将其视为研究级而非生产就绪模型的描述。内容在编辑上是不同的,因为上下文在编辑上是不同的。第三,新增了一个“现实世界使用信号”部分,报告点赞与下载的互动比率、作为模型多功能性代理的标签数量,以及从 HuggingFace 元数据中获取的作者组织规模。这些值在不同模型间绝不相同。该部分无法模板化,因为其输入永远不是恒定的。
The indie games rewrite: audienceWidth × priceTier
独立游戏页面的重写:受众宽度 × 价格层级
findindiegame.com 的重写有一个额外的限制:我必须完全删除 Steam 描述,而不仅仅是在它周围添加内容。保留逐字引用的 Steam 描述并用原创文本包围它并不能解决抓取内容的问题——页面中间依然存在来自第三方的逐字块。我删除了整个“关于”部分。现在出现的所有内容都源自我们自己存储的数据:good_for 列表、avoid_if 列表、相似游戏连接以及 ETL 生成的元数据。摄取 Steam 和 itch.io 数据的 ETL 流水线收集的字段比我之前在页面模板中使用的要多。“我们如何看待这个游戏”部分现在由一个 4×6 的矩阵生成:四个受众宽度类别(源自 good_for 条目的数量),与六个价格层级类别(源自存储的价格数字)交叉组合:
const a