本文约 3,894 字,预计阅读 10 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:两个都说”没问题”,Search Console 却在报错
结构化数据上线后最让人困惑的一幕是:本地用 Google 的测试工具跑一遍全绿,两周后 Search Console 的富媒体结果报表里却躺着一串错误。或者反过来:某个非 Google 支持的自定义类型在 validator 里一片报错,但丝毫不影响页面展现。这不是工具坏了,而是你很可能把两套定位完全不同的工具当成了同一个东西。Rich Results Test 回答的是”这段标记能不能在 Google 搜索结果里拿到某种富媒体形态”,Schema Markup Validator 回答的是”这段标记在 schema.org 词汇层面有没有写错”。前者属于 Google 的产品政策判断,后者属于词汇表语法判断,两者的错误清单只在小部分重叠。
原理分析:两个判断层,错误清单交叉但不等同
可以把结构化数据看成一次”编译 + 上架”的过程。Schema Markup Validator 相当于编译器:检查 @type 是不是 schema.org 里真实存在的类型、属性名有没有拼错、该类型是否需要某个属性组合、嵌套对象有没有写错层级。它对”Google 会不会展示”不发表意见,也不关心你的内容是否违反某个政策(比如自评自测)。
Rich Results Test 相当于上架审核:先确认类型在 Google 的支持清单里,再按 Google 自己的若干对于必填/推荐字段规则检查,最后告诉你”有资格 / 无资格”。它不会指出某个冷门属性的拼写问题,因为 Google 本来就只读它关心的那几个字段。
| 维度 | Rich Results Test | Schema Markup Validator |
|---|---|---|
| 维护方 | Google Search | schema.org 社区与 Google 合作维护 |
| 校验依据 | Google 富媒体结果文档 | schema.org 词汇表定义 |
| 能否查新建 adolesc 型一般 Jacobi | 只认 Google 支持的类型 | 认可词汇表内的全部类型 |
| 是否判断展示资格 | 是 | 否 |
| 输入方式 | URL / 代码片段 | URL / 代码片段 |
| 典型输出 | 检测到的类型、必填缺失、警告 | 未知类型、未知属性、推荐属性缺失 |
另一个重要差异是抓取视角。Rich Results Test 走 URL 模式时,会以 Googlebot 的身份实际抓取页面,因此 robots.txt 拦截、需要登录、CDN 按 UA 返回不一样的内容,都会被工具忠实反映出来。Schema Markup Validator 的 URL 模式同样要抓取,但因为它不参与资格判断,很多人用它来验证”能不能拿到数据”。
此外要注意:工具里的”警告(Warnings)”不会阻断富媒体结果,”错误(Errors)”会。很多新手看到几行黄色警告就以为完了,实际上那部分常常是可选字段。
保姆级实操
第一步:先过 Schema Markup Validator,把词汇错误清干净
开发阶段用它最省事,能直接揪出 agregateRating(少写一个 g)、FaqPage(大小写错误)这类拼写问题,这些问题在 Rich Results Test 里往往表现为”什么都没检测到”,非常难猜。
第二步:再过 Rich Results Test 判断资格
同一个 URL 贴进去,重点看三块:检测到的类型是否包含你期望的那个、Errors 列表、以及”Google 搜索结果预览”区域是否出现对应形态。注意:预览缺失不等于标记有问题,比如 FAQPage 现在本来就不给普通站点展示,这是政策而非错误。
第三步:区分”遗迹只有一个 crawler 能看到”的情况
URL 模式与代码模式结论不一致时,八成是抓取问题。核对清单:robots.txt 是否放行、是否有 noindex、是否需要登录、CDN 是否对 Googlebot 做了特殊返回。
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" -sL "https://mimangfei.com/sample-post/" | grep -c 'application/ld+json'
把这个数字与浏览器里查看源代码得到的数量对比,不等就说明存在 UA 差异。
第四步:批量体检全站 JSON-LD
逐页贴 URL 效率太低,用脚本一次性列出全站标记,并把重复节点挑出来:
import json, re, urllib.request, urllib.error
def fetch(url):
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1)"})
return urllib.request.urlopen(req, timeout=20).read().decode("utf-8", "ignore")
def collect(text):
out = []
for block in re.findall(r'<script type="application/ld\+json"[^>]*>(.*?)</script>', text, re.S):
try:
out.append(json.loads(block.strip().rstrip(",")))
except json.JSONDecodeError as e:
out.append({"__parse_error__": str(e)})
return out
if __name__ == "__main__":
html = fetch("https://mimangfei.com/sample-post/")
nodes = collect(html)
seen = {}
for n in nodes:
for t in ([n.get("@type")] if isinstance(n, dict) else []):
if t:
seen[t] = seen.get(t, 0) + 1
print("nodes:", len(nodes), "types:", seen)
第五步:把结论落到 GSC 报表
工具只代表当下快照,长期要看 Search Console 的富媒体结果报表,错误处理流程见GSC 结构化数据报表的错误修复流程。
第六步:把它做成发布前的固定动作
在 CI 或发布 checklist 里加一条:重要模板改动后,用代表性 URL 跑两轮工具并截图留档。成本几乎为零,却能挡住绝大多数回归。
常见踩坑
- 只跑 Rich Results Test 就收工:词汇错误它不负责,建议双跑。
- 把 Warnings 当 Errors 处理:黄色只是优化建议,不会阻断展示。
- 用本地地址
http://localhost测 URL 模式:工具抓不到,必须换成线上可访问 URL 或用代码模式。 - 缓存未刷新导致改了没生效:测试前先清 CDN 与页面缓存。
- 只看 latency 首页,忽视模板级页面: produktlist、栏目页常常是错误重灾区。
- 案例:某个外贸站为防止”轻量套路”给敏感城市的访客返回简化版 HTML(无 JSON-LD),本地 Charles 抓包一切正常,但 Rich Results Test 的 URL 模式死活检测不到 Product 节点。最后用 Googlebot UA 的 curl 才发现 CDN 侧对海外 IP 返回了简化版。整改后把结构化数据从 CDN 缓存策略里排除,两轮校验结果才一致。工具不一致时,第一嫌疑永远缓存与 UA。
- 误以为 Tool 通过就等于”一定有富媒体”:这两者之间是”必要条件”而非”充分条件”。
总结
判断标准:词汇层面的错误找 Schema Markup Validator,展示层面的资格找 Rich Results Test,长期稳定性看 Search Console。行动清单:开发不怕—先用 validator 清词汇 → 上线前 Rich Results Test 判资格 → 出现分歧先查 UA 与缓存 → 脚本批量盘点全站标记 → 记入发布清单 → GSC 报表收尾。养成这套顺序后,结构化数据的排查时间通常能从”半天”压到”十分钟”。若你的站点由插件与主题多方输出,还需要配合WordPress 上 Schema 的实现方式对比确定唯一数据源。
