OGKit

社交爬虫 User-Agent 真相表:按 UA 分叉内容的代价

  • open-graph
  • 爬虫
  • user-agent
  • 分叉

你在 Chrome 打开线上页:新主视觉、正确的 og:title、新的 og:image。市场同事把同一 URL 丢进 Slack,卡片仍是上季度活动图和 A/B「对照组」模板里的标题。

不是标签被半夜改坏了,而是两个不同的 User-Agent 打到同一路径,拿到了两份不同的 HTML。机器人那条链路还在旧 CMS 布局;人类已经看到了改版。

这篇只谈这件事:社交爬虫自称是谁、会不会跑 JS、怎么用 curl 自证,以及按 UA 分叉内容什么时候是修复、什么时候是事故。

同一 URL,两个世界

机器人与浏览器分叉的常见机制:

机制 爬虫拿到的 你在浏览器里看到的
SSR / SPA 壳 初始 HTML 里 meta 空或占位 hydration 之后才有标签
A/B 或个性化 对照 / 默认变体 胜出变体或登录态体验
Bot 对抗 / 挑战页 403、验证页或极简挑战 HTML 过 JS / cookie 后的完整页
CDN / WAF 规则 对已知 bot UA 的另一缓存键或拦截 浏览器边的热缓存
故意的「bot HTML」 只服务分享的精简 markup 完整营销页

前四类经常被误诊成「Open Graph 坏了」。第五类可以合理(不必为爬虫吐 2MB SPA 壳),但活动结束后若只改人类模板、忘了 bot 模板,就会变成事故。

安全先讲清楚:不要把「敏感信息只放在非 bot 分支」当成安全措施。 爬虫和攻击者都能自己选 User-Agent。只对浏览器暴露的内容,对任何会改 UA 的人仍然是公开的。

User-Agent 真相表

下表来自 OGKit 的平台档案(@og-kit/core)。每一行都带来源核实日期。没有可靠数字的地方写 未知 / unverified——不编造 TTL

平台 User-Agent(代表性) 执行 JS? 分享缓存 TTL 刷新路径 来源 · 核实
Facebook / Meta facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) 未知 Sharing Debugger 重新抓取 官方 · 2026-07-01
X (Twitter) Twitterbot/1.0 常被引用约 7 天(非官方固定值) Card Validator / 改 URL 后重分享 UA 官方;TTL 社区 · 2026-07-01
LinkedIn LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com) 约 7 天(社区) Post Inspector 社区 · 2026-07-01
Slack Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots) 未知 重新分享(无公开 debugger) UA 官方 · 2026-07-01
Discord Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com) 未知 改 query 或 embed 工具 社区 · 2026-07-01
WhatsApp WhatsApp/2.0(存在变体;常复用 Meta 爬虫基础设施) 未知 无公开 debugger;等待或改 URL 社区 · 2026-07-01
Telegram TelegramBot (like TwitterBot) 未知 @WebpageBot 或重分享 社区 · 2026-07-01
Googlebot(对照) Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) (渲染服务) 与 OG 卡无关 Search Console URL 检查 官方 · 2026-07-01

字段级细节(图片字节预算、截断、字段优先级)在线上的平台档案页——同一数据源,带出处徽章。

怎么读这张表

  1. 社交 OG 爬虫不跑你的 JavaScript。og:* 只在 hydration 后出现,卡片就是空的。所以才会有「DevTools 里正常、LinkedIn 上没有」。相关规则:og-tags-require-javascript
  2. Google 不是社交预览爬虫。 只为 Googlebot 优化、或只在浏览器里自测,不能证明 Slack 或 Meta 看到同一份 HTML。
  3. TTL 列不是 SLA。 来源是 communityunverified 时,只当规划参考。改标签或换图后,走各平台官方 rescrape(rescrape 助手),不要干等传闻中的过期时间。

自己验证(curl -A

若中间件按 UA 分流,不要只信浏览器「查看源代码」。按机器人身份抓:

URL="https://example.com/launch"

# 基线(通用浏览器向 UA)
curl -sL -A "Mozilla/5.0" "$URL" | tee /tmp/human.html | grep -iE 'og:title|og:image' | head

# Meta
curl -sL -A "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" \
  "$URL" | tee /tmp/fb.html | grep -iE 'og:title|og:image' | head

# X
curl -sL -A "Twitterbot/1.0" "$URL" | tee /tmp/x.html | grep -iE 'og:title|og:image|twitter:' | head

# LinkedIn
curl -sL -A "LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)" \
  "$URL" | tee /tmp/li.html | grep -iE 'og:title|og:image' | head

然后比文档,不靠感觉:

# 正文哈希(忽略响应头日期;任何 HTML 漂移都会变)
sha256sum /tmp/human.html /tmp/fb.html /tmp/x.html /tmp/li.html

# 只比 meta
diff -u \
  <(grep -iE 'property="og:|name="twitter:' /tmp/human.html | sort) \
  <(grep -iE 'property="og:|name="twitter:' /tmp/fb.html | sort)

也要看 状态码与响应头

curl -sI -A "facebookexternalhit/1.1" "$URL" | head -20

你 200、bot 403 或挑战页,是经典 WAF 误伤。可与空白卡片清单对照:为什么你的 Open Graph 卡片一片空白

对 OG 而言什么叫「相同」

全文 HTML 完全一致最理想,但不总是必须。分享正确性至少要在各社交 UA 间一致:

  • og:titleog:descriptionog:imageog:urlog:type
  • 绝对 HTTPS 图片 URL,无需登录即可 200
  • 不要用 bot 专用插页顶替真实文档

若营销 HTML 与 bot HTML 有意不同,把 bot 模板当成一等发布面写进发版清单——和换主视觉同优先级。

何时该统一 HTML(何时分叉可接受)

优先同一份 HTML,当:

  • 你并没有在刻意维护单独的分享模板
  • A/B 或边缘个性化会按 cookie 改标题 / 主视觉
  • Bot 管理对公开营销 URL 出挑战页
  • 「优化」只针对 Googlebot 或 CWV,却波及了 unfurl

有意分叉可以接受,当:

  • 给爬虫 SSR 薄分享壳、给用户重客户端应用, OG 值来自同一事实源
  • 仅为抓取体积去掉非分享 chrome,不改变 meta 含义

永远不 OK:

  • 把隐私数据只放在非 bot 分支当「安全」
  • 对 bot 长期返回错误 meta 的 200,人类却看到真活动
  • 人类模板已发版、bot 模板忘了同步

OGKit 把意外分叉编码为 ua-content-diverged:不同 User-Agent 拿到不同 HTML body 哈希。这是 warn,不是自动判定「你在 cloaking」——但它是逼人眼看一眼的信号。

检查清单

  • 不跑 JS 的 curl 里能看到你期望的 og:*
  • curl -A facebookexternalhit/1.1(以及至少一个其他社交 UA)不被拦
  • 各 UA 正文或 meta 哈希一致,或差异有意且有文档
  • Bot 对抗规则对已知社交爬虫放行公开分享 URL
  • 改标签 / 换图后走官方 rescrape,不依赖编造的 TTL
  • 秘密靠鉴权,不靠 User-Agent

下一篇读什么

  1. Open Graph 到底在解决什么 — 完整分享工作流,不止写标签
  2. 为什么你的 Open Graph 卡片一片空白 — 五种失败模式
  3. 平台档案 — 在线 UA 字符串、图片预算与出处
  4. SPA / SSR 抓取缺口、缓存与 rescrape、CI 门禁 — 系列后续

做一次多 UA 扫描

把公网 URL 贴进首页扫描。OGKit 用与上表同一套平台档案里的 User-Agent 抓取,输出含 ua-content-diverged 在内的规则发现,并在 HTML 已对但卡片仍旧时指向官方 rescrape。

公网爬虫够不到的 localhost / 内网,走浏览器扩展路径——系列后面会写。产品要做的不是更漂亮的假卡片,而是摊开每个 bot 真正拿到的那份文档