直接回答:结构化数据加了没效果,绝大多数情况不是类型选错,而是四个基础问题之一——页面根本没被索引、JSON-LD 格式让解析器读不到、地址用的是示例域名、数据与页面可见内容对不上。这四项按顺序查一遍,比研究 Schema.org 的细节有用得多。

结构化数据不负责"被收录",先确认页面能被抓到

一个前提要先说清楚:结构化数据的作用是把页面里已经存在的信息表达得更明确,它不会让一个没被收录的页面变得可检索。

所以排查的第一步不是看代码,而是确认:

  • 页面能被爬虫抓取(返回 200,没有被 robots.txt 或 CDN 拦)
  • 页面已经进入索引(搜 site:域名 能找到)
  • 内容本身回答了某个真实问题

**这三条不成立时,结构化数据写得再标准也没有意义。**前两条的验证方法见《为什么 AI 从来不提我的网站》

检查点一:格式错误的 JSON-LD 会被静默忽略

格式错误的 JSON-LD 会被解析器直接忽略,而且不会在页面上显示任何异常——这是最容易被漏掉的一类问题。

常见错误:

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 错误一:多了一段多余的花括号,JSON 不合法 -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting"
}}
</script>

<!-- 错误二:引号被模板转义,输出成了 &quot; -->
<script type="application/ld+json">
{&quot;@type&quot;: &quot;BlogPosting&quot;}
</script>

第二种情况在静态站点生成器里很常见:模板引擎对字符串做了 HTML 转义,结果 " 变成了 &quot;,JSON 直接失效。

验证方式:直接查看页面源码,把 <script type="application/ld+json"> 里的内容复制出来跑一次解析:

1
2
3
4
5
6
7
8
9
10
11
12
curl -s https://example.com/posts/hello/ \
| python3 -c "
import sys, re, json
html = sys.stdin.read()
blocks = re.findall(r'<script type=\"application/ld\+json\"[^>]*>(.*?)</script>', html, re.S)
print('找到', len(blocks), '个 JSON-LD 块')
for i, b in enumerate(blocks, 1):
try:
json.loads(b); print(f' 第 {i} 个:合法')
except Exception as e:
print(f' 第 {i} 个:解析失败 →', e)
"

输出里有任何一个"解析失败",就先修这个,别的都不用看。

检查点二:@idurl 必须是真实的绝对地址

这是从教程里复制代码时最容易埋下的坑。

大多数示例代码用 example.com 占位,直接复制就会得到这样的输出:

1
2
3
4
{
"@type": "WebPage",
"@id": "https://example.com/posts/structured-data/"
}

后果是实体标识指向了别人的域名:模型在理解"这篇文章属于谁"时拿到的是错误信息,等于白写。更隐蔽的情况是同一页面里混用相对路径和绝对路径,导致同一个实体有两个标识。

规则很简单:

  • @idurl 一律写完整的绝对地址,包含 https:// 和域名
  • 所有出现的地方必须完全一致,包括结尾有没有斜杠
  • 上线前全局搜一次 example.com,确保没有残留
1
2
# 在构建产物里搜占位域名
grep -rn "example.com" public/ | head

检查点三:数据只能声明页面上真实存在的信息

结构化数据有一条硬规则:它只能声明页面上真实存在的信息。

声明了页面上没有的内容,属于误导性标记,轻则被忽略,重则影响整个站点的可信度。常见的不一致:

不一致的情况 后果
headline 和页面标题不一样 标题信息不被采信
datePublished 与页面上显示的日期不同 时效性判断出错
author 指向一个访问不了的作者页 作者实体无法建立
声明了 FAQPage,页面上却没有对应问答 该块整体被忽略
image 地址返回 404 图片相关字段失效

验证方式:把 JSON-LD 里的字段和页面上肉眼可见的内容逐项对一遍,尤其是标题、日期、作者、图片这四项。图片地址还要单独确认能打开。

检查点四:单条数据不够,要声明实体之间的关系

单打独斗的一条 BlogPosting 信息量有限。让模型理解"这篇文章属于哪个站点、由谁写的、在什么位置",需要多条数据互相引用。

四种最有价值的关系(详细写法见《结构化数据怎么做才对 GEO 有用》):

类型 回答的问题
BlogPosting 这是什么内容
BreadcrumbList 它属于哪个主题路径
FAQPage 它直接回答了哪些问题
Person 作者是谁,可信度如何

如果只加了 BlogPosting 就发现没效果,问题往往在这里——不是数据错了,而是信息量不够支撑一次"引用决策"。

用工具验证,别靠肉眼判断

排查完上面四项后,用官方工具做一次确认:

工具 用途
Google 富结果测试 检查能否被解析、哪些字段缺失
Schema Markup Validator 校验语法与类型是否规范
搜索平台的抓取统计 确认页面确实被收录

注意工具的作用边界:**它们能验证"数据是否合法",不能验证"是否会被 AI 引用"。**后者只能通过在多个平台上用固定问题采样来观察,方法见《怎么衡量 GEO 有没有效果》

常见问题(FAQ)

结构化数据加完多久能看到变化?

没有固定周期,取决于页面是否被重新抓取。通常几周到一两个月。如果页面本身没被索引,等多久都不会有变化——这也是为什么排查要从抓取和索引开始。

加了 FAQPage 但搜索结果里没显示问答,是失败了吗?

不一定。FAQPage 结构化数据对 GEO 的价值在于让模型更容易提取问答对,而不仅仅是搜索结果的富摘要展示。两个平台的展示策略也各不相同,不展示不代表数据没被使用。

多个 JSON-LD 块放在同一个页面会不会冲突?

不会。解析器会把同一页面里的多个块合并理解。实践中更推荐用 @graph 把相关内容组织在一个块里,便于维护,但分开放多个块同样有效。真正的问题不是块的数量,而是实体之间有没有互相引用、标识是否一致

用了 WordPress 或 Hexo 的插件,还需要自己检查吗?

需要。插件保证的是"输出格式",不保证"内容正确"——尤其是 @id 指向的域名、作者页地址、日期格式这些需要结合站点实际情况调整的字段。插件装完必须抽查两三个页面的源码。

小结

  • 结构化数据不负责收录,先确认页面能被抓取和索引。
  • JSON-LD 格式错误会被静默忽略,上线前跑一次解析验证。
  • @idurl 必须是真实绝对地址,且全局统一。
  • 数据只能声明页面上真实存在的信息。
  • 单条 BlogPosting 信息量不足,需要多条数据互相引用。

如果你加了结构化数据还是不生效,欢迎到留言板贴出页面地址和 JSON-LD 片段,一起看看卡在哪一项。

站内搜索

没有找到内容!