via https://ipullrank.com/cloaking-for-llms
在开始之前,我们先挑明一个显而易见的事实。伪装是指向普通用户展示的内容与向搜索引擎展示的内容不同,其目的是操纵搜索引擎的排名表现。这种做法违反 Google 的指南。
如果你想继续留在 Google 的索引中,就不应该对 Google 做伪装。
话虽如此,ChatGPT 并没有类似的指南。而且,ChatGPT 的“爬虫”(或称“代理”)并不渲染内容。Google 看重的是“信息增益”,而 ChatGPT 同时也成了你的竞争对手快速窃取你内容并重新发布的机制。
既然如此,为什么要让他们更容易得手呢?
什么时候对大语言模型做伪装是合理的?
让我感到困惑的是,生成式 AI 公司在训练模型和推理上投入了数十亿美元的算力,却在渲染 JavaScript 和缓存网页上止步不前。然而,这正是我们的机会。
这方面的数据差异非常明显。Vercel 和 MERJ 分析了超过 5 亿次 GPTBot 抓取记录,没有发现任何执行 JavaScript 的证据。ClaudeBot 大约在 24% 的情况下会抓取 JS 文件,GPTBot 约为 11.5%——但两者都不会实际运行它们。另一项针对 23 个主流 AI 爬虫的分析发现,其中 69% 根本无法执行 JavaScript。Googlebot 会渲染,Bingbot 会渲染。其他所有爬虫——GPTBot、ChatGPT-User、OAI-SearchBot、ClaudeBot、PerplexityBot、Bytespider、CCBot、Meta-ExternalAgent——只会获取原始的初始 HTML,然后就离开了。
假设你有一个网页,上面发布了你独有的丰富数据:比如一项专有的基准研究、一个你花了六个月收集的数据集、一项针对 2000 名从业者的内部调查,或者一个你根据多年客户工作整理出的独特框架。这类内容需要真正的时间和金钱才能产出,而且别人没有。
我可以轻松地运行这样的提示词:{阅读这个页面,提取所有数据,然后为[某个网站]重写一个新版本}。现在,你那精彩、独有的内容就变成我的了,你的“信息增益”优势也就消失了。
针对大语言模型的 JavaScript 伪装
这里的思路并不是说我们要向 ChatGPT 展示用户看不到的东西(虽然你也可以这么做,比如白底白字,或者根据用户代理添加文本,这些都是可行的手段)。
我提出的是:从页面中移除某些内容,从而保持你的优势。
实际上,我们要做的是:用特定的 class 标记内容,并且仅通过客户端渲染这些区块。然后,我们只需为所有大语言模型的用户代理屏蔽掉我们所用的那个 JS 文件。
Google 和 Bing 不受影响,而 ChatGPT、Perplexity 等则永远看不到这些内容。
这种机制之所以有效,是因为整个 AI 爬虫生态系统(Gemini 除外,它跑在 Google 的基础设施上)仍然停留在 2010 年的工作方式:发送 HTTP 请求,获取初始 HTML 响应,然后离开。如果你的“差异化”内容存在于一个 <div data-llm-protected> 中,并且这个 div 的内容是由一个你已针对那些用户代理屏蔽了的 JS 文件填充的,那么爬虫就根本无法看到它。对它们来说,页面的那个部分根本不存在。与此同时,真实用户在浏览器中,以及会渲染页面的 Googlebot,看到的则是完整体验。
这恰恰是我们过去 20 年里所有关于伪装讨论的反向操作。过去的问题是:“我如何向搜索引擎展示我向用户隐藏的内容?” 而现在的问题是:“我如何向用户展示我向一个不配得到它的爬虫所隐藏的内容?”
以 Markdown 格式提供页面可以提升速度
当一个页面加载缓慢时,某些 AI 爬虫会返回 499 状态码,导致该页面无法被纳入答案或引用。以 Markdown 格式提供页面可以获得更快的首字节时间(TTFB),并提高被引用的可能性。
Cloudflare 自己的数据很有启发性:他们自己一篇公告的 HTML 版本消耗了 16,180 个 token,而 Markdown 版本只有 3,150 个。这相当于将爬虫需要处理的内容减少了 80%。下载更少、解析更少、TTFB 更快,你真正越过超时窗口并被引用的几率就大得多。
Cloudflare 现在已经把这个做成了一项功能(“面向代理的 Markdown”),但你不需要使用他们的托管产品也能实现。你只需要一个 Worker:当用户代理是 LLM 时,响应 Markdown;其他时候响应 HTML。我们下面就会具体实现。
保持你的优势,为大型语言模型做伪装
总结一下:AI 爬虫生态系统不执行 JavaScript,不遵循 Google 的指南(因为它们不是 Google),而且被你的竞争对手积极用来抓取和改写你的作品。没有任何政策理由让你把自己最好的内容喂给它们;而且,当你确实要喂给它们一些内容时,以 Markdown 格式提供还能带来显著的速度和被引用方面的好处。如果你花了真金白银产出了原创数据、框架或研究,那么默认做法——“让每个 AI 爬虫免费、完整地拿走,而我的竞争对手下周二之前就能在他们的域名上重新发布”——这不是一个策略,而是一个疏忽。
下面是使用 Cloudflare Workers 解决这个问题的方法。
步骤 1:在域上设置一个 Worker
如果你已经在使用 Cloudflare,这部分很简单。安装 Wrangler,认证,然后创建一个新的 Worker:
bash
npm install -g wrangler wrangler login wrangler init llm-cloaker cd llm-cloaker
在 wrangler.jsonc 中,设置指向你域名的路由(如果你只想将其应用于特定路径,也可以设置路径模式):
json
{
"name": "llm-cloaker",
"main": "src/index.ts",
"compatibility_date": "2025-03-07",
"routes": [
{ "pattern": "yoursite.com/*", "zone_name": "yoursite.com" }
]
}
步骤 2:检测大语言模型的用户代理
Workers 的 fetch 处理程序可以直接访问请求头。构建一个你想视为 LLM 流量的用户代理列表。当前值得覆盖的列表如下:
typescript
const LLM_USER_AGENTS = [
"GPTBot", // OpenAI 训练
"ChatGPT-User", // OpenAI 用户触发的抓取
"OAI-SearchBot", // OpenAI 搜索/引用
"ClaudeBot", // Anthropic
"anthropic-ai", // Anthropic(旧版)
"PerplexityBot", // Perplexity
"Perplexity-User", // Perplexity 用户触发
"CCBot", // Common Crawl(许多模型的训练数据)
"Bytespider", // ByteDance
"Meta-ExternalAgent",// Meta
"Amazonbot", // Amazon
"Applebot-Extended", // Apple AI 训练(注意:不是普通的 Applebot)
"Google-Extended", // Google AI 训练(注意:不是 Googlebot)
"Diffbot",
"cohere-ai",
];
function isLLMAgent(ua: string): boolean {
if (!ua) return false;
return LLM_USER_AGENTS.some(bot => ua.includes(bot));
}
关于两个重要的排除项:不要把 Googlebot 或 Bingbot 放进这个列表。Google-Extended 和 Applebot-Extended 是 AI 训练代理。它们与常规的搜索爬虫是分开的,而这些才是你想当作 LLM 处理的代理。
步骤 3:针对 LLM 代理屏蔽受保护的 JS 文件
这就是伪装机制的核心。选择一个文件名,用于填充你受保护内容的 JS 文件,比如 /js/protected-content.js。当请求方是 LLM 时,Worker 对该文件返回 404(或一个空的 200);对其他所有请求则正常放行:
typescript
export default {
async fetch(request: Request): Promise<Response> {
const ua = request.headers.get("User-Agent") || "";
const url = new URL(request.url);
const isLLM = isLLMAgent(ua);
// 对 LLM 爬虫屏蔽受保护的 JS 文件
if (isLLM && url.pathname === "/js/protected-content.js") {
return new Response("", {
status: 404,
headers: { "Cache-Control": "no-store" }
});
}
// ... 继续步骤 4
return fetch(request);
}
};
在页面本身上,将你的受保护内容包裹在一个容器中,该容器在源 HTML 中是空的,然后由 protected-content.js 在客户端填充。真实用户执行 JS 并看到内容。Googlebot 执行 JS(它会渲染)并看到内容。每个 LLM 爬虫获取该 JS 文件时得到 404,因此永远不会执行它,只会看到一个空容器。
步骤 4:对内容 URL 上的 LLM 代理提供 Markdown
同一个 Worker,第二个职责。当 LLM 代理请求一个 HTML 页面时,获取源站响应并在返回之前将其转换为 Markdown。有几种方法可以做到这一点——最干净的方法是预先为你的重要页面生成对应的 .md 版本并提供它们,因为运行时将 HTML 转换为 Markdown 可能会比较粗糙,还会增加延迟(这反而违背了提速的初衷):
typescript
// 预生成的方法:如果你有 /post/foo.html,同时也发布 /post/foo.md
async function serveMarkdownIfAvailable(
request: Request,
url: URL
): Promise<Response | null> {
const mdUrl = new URL(url.toString());
// 将 /any/path 或 /any/path/ 映射到 /any/path.md
mdUrl.pathname = mdUrl.pathname.replace(/\/$/, "") + ".md";
const mdResponse = await fetch(mdUrl.toString(), {
headers: request.headers
});
if (mdResponse.ok) {
return new Response(mdResponse.body, {
status: 200,
headers: {
"Content-Type": "text/markdown; charset=utf-8",
"X-Robots-Tag": "noindex, nofollow",
"Cache-Control": "public, max-age=3600"
}
});
}
return null;
}
将其接入主处理程序:
typescript
export default {
async fetch(request: Request): Promise<Response> {
const ua = request.headers.get("User-Agent") || "";
const url = new URL(request.url);
const isLLM = isLLMAgent(ua);
// 1. 对 LLM 代理屏蔽受保护的 JS
if (isLLM && url.pathname === "/js/protected-content.js") {
return new Response("", { status: 404 });
}
// 2. 对于 HTML 页面,向 LLM 代理提供 Markdown
const isHtmlRequest = !url.pathname.match(
/\.(js|css|png|jpg|jpeg|gif|svg|webp|ico|woff2?|mp4|pdf)$/i
);
if (isLLM && isHtmlRequest) {
const md = await serveMarkdownIfAvailable(request, url);
if (md) return md;
}
// 3. 其他所有情况返回正常页面
return fetch(request);
}
};
如果你不想预生成 Markdown,也可以在边缘使用 HTMLRewriter 加上一个小型的 Turndown 风格转换器来进行 HTML 到 Markdown 的转换,或者直接启用 Cloudflare 的“面向代理的 Markdown”功能,让它为你做转换。预生成能产生更好的输出结果,运行时转换则上线更快。
步骤 5:部署并验证
bash
wrangler deploy
然后验证两种行为。你需要确认:一个 LLM 用户代理得到的是伪装后的行为,而普通浏览器得到的是完整页面。最快的方式是用 curl:
bash
# 应该返回 404(或空内容) curl -A "GPTBot/1.2" https://yoursite.com/js/protected-content.js -I # 应该返回 Markdown curl -A "GPTBot/1.2" https://yoursite.com/your-best-post -I # 应该返回正常的 HTML 页面,并且 JS 文件可访问 curl -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \ https://yoursite.com/your-best-post -I
部署前的实操注意事项
在你不加区分地部署这种伪装技术之前,有几点需要考虑:
- 不要在需要出现在 AI 概览或 ChatGPT 搜索中排名的内容上做伪装。
这项技术是为你自己的护城河准备的:专有数据、原创研究、你投入最高心力的框架。你的漏斗顶部 SEO 内容仍然应该对 LLM 完全可见,因为对于那类内容,被引用的本身就是目标。伪装的是资产,而不是认知内容。 - 存在欺骗者。 一个意志坚定的竞争对手会使用 Chrome 的用户代理(而不是 GPTBot)来抓取。基于用户代理的伪装能阻止掉 95% 的“偷懒型”自动提取(这已经包括了大部分,包括实际的训练和引用爬虫)。对于那 5% 的坚定分子,你需要机器人管理、速率限制和 Cloudflare 的已验证机器人信号。那将是另一篇文章的内容。
- 测试 Googlebot 看到的内容。 部署后,通过 Google 的网址检查工具运行你的页面。受保护的内容应该出现在渲染后的 HTML 中。如果没有,那你就破坏了你的 SEO,这比 AI 爬虫吃掉你的数据要严重得多。
- 每月更新你的用户代理列表。 新的 LLM 爬虫不断出现。上面的列表在撰写本文时是准确的。六个月后就不一定了。
以上就是全部技术方案。四十行 Worker 代码、一个 JS 文件的命名约定,以及一个可选的、在 HTML 旁生成 Markdown 的构建步骤。最终结果是:你花了真金白银产出的内容依然属于你,你的“信息增益”优势保持不变,而那些原本下周就要把它喂给你竞争对手的机器人,则得到了一个礼貌的空容器。
