JSONLD结构化数据生成器

填一张表,拿到一段可以直接粘进 <head> 的 schema.org 代码。生成后会做第二层校验——JSON.parse 抓不到的错(类型名拼错、日期不是 ISO 8601、@id 写成片段)这里逐条报出来。

✓ JSON 语法✓ @context✓ @type 可识别✓ 必填属性✓ URL 格式✓ 日期 ISO 8601

六个徽标从左到右分别验什么

  • JSON 语法:把刚序列化的结果用 JSON.parse 读回来,验证输出一定能被解析。
  • @context:必须存在且等于 https://schema.org(带 s)。缺了所有 @type 失去语义。
  • @type 可识别:类型名大小写敏感、必须在 schema.org 词表内。"Artical"、"article" 都是无效值。
  • 必填属性:Article 要 headline,Organization 要 name,WebSite 还要 url。
  • URL 格式:url 与 @id 必须是 https:// 绝对地址;http://、#org、/post/1 都会被拦下。
  • 日期 ISO 8601:只接受 YYYY-MM-DD 或 YYYY-MM-DDTHH:MM:SS+08:00。

两层校验查的错完全不重叠:JSON.parse 抓尾逗号、单引号、括号不配对这三类语法错;它抓不到类型名拼错、类型名小写、缺 @context、日期格式错、@id 用片段——那五类在 JSON 语法上完全合法,爬虫会静默丢弃整个块。

使用方法

  1. 在第一个下拉框里选 schema.org 类型。类型一旦选定,下方必填与推荐属性会跟着切换——Article 要 headline,Organization 要 name,WebSite 要 name 加 url。页面打开时默认是 Article,标题框里已经预置了「如何写好一份结构化数据」。
  2. 填标题和页面 URL。URL 必须以 https:// 开头:schema.org 的 url 与 @id 都按绝对 URL 处理,写成 /post/1 这种站点内相对路径在富媒体测试里会被判为无效。
  3. 点「生成代码」(结果区是即时更新的,改完字段就会重出片段)。输出默认是 2 空格缩进,方便肉眼核对;想贴成一行,点「包上 script 标签」会同时给出可直接粘进 <head> 的完整三行形式。
  4. 看结果区下方的徽标行。绿色的表示通过,红色的每一条都写清了哪个字段、允许什么格式——这些是 JSON.parse 发现不了的错误:类型名拼错、日期写成 2026/10/03、@id 写成 #org,这三类在 JSON 语法上完全合法,只有按 schema.org 规则逐条查才能揪出来。
  5. 点「复制片段」把代码带走,粘到 <head> 里 </title> 之后即可。粘完建议用浏览器的富媒体测试工具跑一遍,本页的校验只覆盖 schema.org 语法层面,检测不到「内容与页面实际不符」这类问题。

这个 JSONLD结构化数据生成器能解决什么问题

一是避免「JSON 合法但结构化数据无效」这个最贵的坑。绝大多数 JSON-LD 出错的地方,JSON 语法本身是对的:"@type": "Artical" 拼错了字母、"article" 小写了首字母、"datePublished": "2026/10/03" 用了斜杠。这些片段粘进页面不报错、控制台干净、爬虫也不吭声,只是永远拿不到富媒体摘要。等你发现时往往已经上线几个月。本页把这两类错误分开报,第一类报「第几行第几列语法错」,第二类报「哪个字段不符合 schema.org 规则」。

二是快速产出多类型页面级的 @graph。一个内容页通常要同时声明 Organization(站点主体)、WebSite(带 SearchAction)和 WebPage(本页),三者用 @id 互相引用。本页的「WebSite」档可以直接产出这套结构,省掉手写时最容易出错的 publisher / isPartOf 嵌套。

三是核对已有片段的字段是否填齐。从旧项目里拷来一段 JSON-LD,粘到本页的校验思路里逐条对:必填属性缺了没有、推荐属性漏了没有、日期格式过没过。缺 image 的 Article 拿不到文章卡片,缺 offers.priceCurrency 的 Product 拿不到价格展示——这些不是「有总比没有好」,而是缺了关键属性等于白做。

四是批量对齐同一套实体。站点有几十个页面时,@id 必须前后一致才能被识别成同一个实体。用本页生成一次基准片段,之后所有页面只改 URL 和标题,@id 保持不动,这是最省事的做法。

本页不做这些事:不给你自己的页面加结构化数据(本模块已全站移除 application/ld+json,本页自身也不输出这种标签,生成结果仅作文本展示与复制);不联网查询 schema.org 词表;不判断你填的内容与页面是否相符;不做富媒体测试的替代品。要把 JSON 排版得整齐请用「JSON美化打印」,要检查 JSON 语法请用「JSON校验工具」。

原理与规则:两层校验为什么缺一不可

第一层是 JSON 语法校验,用的是 JSON.parse(text)。它只关心引号、逗号、括号配不配。ECMA-404 定义 JSON 语法、RFC 8259 定义交换格式,两者都要求:键与字符串值必须用双引号,不允许尾逗号,不允许注释,不允许 undefined、NaN、Infinity。JSON.parse 抛出的 SyntaxError 在新版 V8 里带位置信息,可以直接定位到行列。

第二层是 schema.org 规则校验,这是本页真正在做的事。它包含四组互不重叠的检查:

① @context 检查。必须存在且等于 https://schema.org(带 s)。写成 http://schema.org 或 schema.org 都不行——JSON-LD 1.1 允许自定义 context 字符串,但搜索引擎只认这一条。缺 @context 时所有 @type 都没有语义,属于致命错误。

② @type 检查。类型名大小写敏感,必须首字母大写:Article 有效,article 无效。拼写错误更隐蔽:"Artical" 在 schema.org 词表里不存在,但它是个完全合法的 JSON 字符串,JSON.parse 不会报错,爬虫会静默丢弃整个块。这一类错误只能靠「比对已知类型清单」发现,所以本页把 8 个常用类型做成下拉框而不是让用户手打——手打就是拼错的来源。

③ 日期格式检查,依据 ISO 8601 / RFC 3339。Google 接受两种写法:仅日期 2026-10-03,或带时区的完整时间戳 2026-10-03T08:30:00+08:00。不接受 2026/10/03、2026年10月3日、Oct 3 2026。这里有个容易忽略的细节:JS 的 new Date().toISOString() 产出的是 Z(UTC) 带毫秒的形式,比如 2026-10-03T00:30:00.000Z,它对应北京时间 08:30。所以直接用 toISOString() 填进 datePublished 不会报错,但时间和用户看到的墙上时间差 8 小时;本页因此不自动取当前时间,而是让你手填或从页面日期里选。

④ @id 与 URL 检查。@id 用于把多个块里的同一实体关联起来,形式必须是完整绝对 URL:https://example.com/#organization。写成 #org 是最常见的错误——单页里看着能跳转,跨页面就完全对不上,实体合并失效。相对路径 /post/1 同理不行。

序列化用 JSON.stringify(obj, null, 2),第二个参数必须传 null。这是个容易记错的签名:JSON.stringify 的第二个参数是 replacer——传数组会只保留数组里列出的键,传函数会改写每个值,只有传 null 才是「原样输出」。第三个参数才是缩进:2 是 2 空格,'\t' 是制表符。本页选 2 空格而不是 4 空格或 Tab,理由是 Google 官方文档与主流 schema 示例都用 2 空格,缩进宽度不影响解析但影响人工 review 时的可读性;实测同一个 Article 片段单行是 180 字节、2 空格缩进是 220 字节,差 40 字节,对页面性能可以忽略。

还有一个纯 JSON 层面的取舍:@type 可以是数组。"@type": ["Article", "NewsArticle"] 表示同时属于两种类型,语义上比 NewsArticle 更宽(后者本身继承前者)。代价是序列化后多几个字符:同样的内容数组形式 82 字节、字符串形式 66 字节。所以能用具体类型就别用数组。

完整示例(数值均为实测)

页面打开时的默认条件是:类型 Article,标题「如何写好一份结构化数据」,URL https://example.com/post/1,作者「张三」,日期 2026-10-03。生成结果共 6 个顶层键,2 空格缩进后 220 字节、单行 180 字节:

键值为什么需要它
@context"https://schema.org"告诉解析器 vocabulary 在哪,缺了整个块无意义
@type"Article"声明实体类型,大小写敏感
headline"如何写好一份结构化数据"Article 唯一的必填属性,搜索结果里显示的标题
url"https://example.com/post/1"本页规范 URL,必须绝对地址
author{ "@type": "Person", "name": "张三" }嵌套对象;AMP 文章要求此字段
datePublished"2026-10-03"ISO 8601 仅日期形式

这个片段能通过全部四组检查,所以结果区下方 4 个徽标全是绿的。如果把日期改成 2026/10/03,「日期格式」徽标立刻转红并指出是哪个字段、允许什么范围:只接受 YYYY-MM-DD 或 YYYY-MM-DDTHH:MM:SS±HH:MM。如果把标题清空,「必填属性」徽标转红,提示 Article 至少需要 headline。

换 @type 为 Organization 时输出变成 4 个键、129 字节(2 空格缩进、单行 112 字节):@context、@type、name、url——URL 从必填降为推荐但仍会输出。换成 FAQPage 时因为多了一层 mainEntity 数组嵌套,缩进后变成 278 字节(单行 197 字节),是三者里最长的。这三个数字能让你对「结构化数据大概要多长」有个直观预期。

输入范围与常用类型属性对照表

下表是本页下拉框覆盖的 8 个类型,外加 4 个常见补充。必填属性是缺了就没有富媒体展示的最小集合,推荐属性是影响展示质量的:

schema.org 类型中文必填属性推荐属性
Article文章headlineauthor / datePublished / image
NewsArticle新闻headlinedateModified / articleSection
Organization组织机构nameurl / logo / sameAs / legalName
Product商品nameoffers.price / priceCurrency / availability
FAQPage问答页mainEntityQuestion.acceptedAnswer.text
BreadcrumbList面包屑itemListElementListItem.position / name / item
WebSite网站首页name / urlpotentialAction → SearchAction
LocalBusiness本地商家name / addresstelephone / geo / openingHours / priceRange
Recipe菜谱namerecipeIngredient / recipeInstructions / prepTime
SoftwareApplication应用nameapplicationCategory / operatingSystem
VideoObject视频name / description / thumbnailUrluploadDate / duration / contentUrl
Person人物nameurl / sameAs / jobTitle

再看十个最常踩的校验错误。左列是错误写法,中间是为什么错,右列是正确写法——这十条里只有前两条能被 JSON.parse 抓到,其余八条在 JSON 语法上完全正确:

错误写法错在哪正确写法
{ "@type": "Article" }缺 @context,所有键失去语义补 "@context": "https://schema.org"
"@type": "Article",尾逗号,JSON 严格语法不允许删掉最后一个逗号
{ '@type': 'Article' }单引号,JSON 只接受双引号改成双引号
"@type": "Artical"类型名拼错,schema.org 无此类型,被静默丢弃"@type": "Article"
"@type": "article"类型名小写,大小写敏感"@type": "Article"
"@context": "http://schema.org"少一个 s,搜索引擎不识别"@context": "https://schema.org"
"datePublished": "2026/10/03"非 ISO 8601 格式"2026-10-03"
"@id": "#org"@id 必须是绝对 URL,片段无法跨页关联"@id": "https://example.com/#org"
"available": "true"布尔值写成了字符串"available": true
"price": "9.90"数值写成了字符串"price": 9.9

边界、精度与常见误读

  • 类型名只认这 8 个(加表格里的 4 个)。schema.org 有 800 多个类型,本页只覆盖搜索富媒体最常用的一批。选不出来的场景(例如冷门行业类型)不要硬套——用更宽的类型:不确定是 Article 还是 NewsArticle,用 Article,因为后者是前者的子类,属性要求完全一致。多写一个泛类型不会有害,写错一个不存在的类型则整个块作废。
  • URL 字段不接受 http 与站内相对路径。本页对 url 与 @id 都做协议校验:必须以 https:// 开头。理由是 @id 承担着跨页面实体合并的职责,协议不同会被当成两个不同实体。生产环境确实还在 http 上的站点,本页会明确报错而不是默默接受——升级到 https 是结构化数据生效的前提。
  • 日期字段有两种合法形式,不要混着加毫秒。2026-10-03 与 2026-10-03T08:30:00+08:00 都合法,但 2026-10-03T08:30:00.000+08:00(带毫秒)在部分消费端解析不一致。页面的输入框接受前两种,第三种会报错并提示改用不带毫秒的形式。另外不要用 toISOString() 的输出:它给的是 UTC 加毫秒,例如 2026-10-03T00:30:00.000Z 对应北京时间 08:30,差 8 小时且格式不理想。
  • URL 字段有长度上限 200 字符,标题 200、作者 80。超长不是错误,但超过 200 字符的 URL 在搜索结果里通常会被截断,反而影响可读性。本页对这三个字段设了 maxlength,超出会直接挡住输入而不是静默截断已有内容。
  • 空标题是错误,不是「生成一个空片段」。任何类型都有必填属性(Article 是 headline,Organization 是 name,FAQPage 是 mainEntity),必填为空时本页拒绝生成并指出是哪个类型的哪个属性缺失,不会给你一段看着能跑、实际拿不到展示的代码。这是本页与「直接让 AI 手写片段」最大的区别。
  • 「JSON 合法」与「结构化数据有效」是两件事。这是本页反复强调的核心:JSON.parse 能发现尾逗号、单引号、括号不配对这三类语法错,但发现不了类型名拼错、类型名小写、缺 @context、日期格式错、@id 用片段这五类。反过来,schema 校验也发现不了「日期合法但填错了」这类语义问题。所以两层都要跑,缺一不可。
  • 本页自身不输出 <script type="application/ld+json"> 标签。本项目模块已全站移除结构化数据标签,本页的定位是给你自己的站点生成代码片段,生成结果仅以文本形式展示在结果区并支持复制。「包上 script 标签」按钮输出的是可复制的文本,不是页面真实 DOM 里的标签——你可以打开开发者工具确认,本页 DOM 里不存在 ld+json 标签。
  • 字节数的差异只影响可读性,不影响解析。2 空格缩进比单行多出的是换行与空格字符,搜索引擎解析时两者等价。上表实测(单行 / 2 空格缩进):Article 180 / 220 字节,Organization 112 / 129 字节,FAQPage 197 / 278 字节,@graph 三节点 433 / 621 字节。所以放心用缩进形式,除非你在做极端字节数敏感的场景。

常见问题

我的 JSON-LD 语法完全正确,为什么搜索结果里还是没有摘要?

语法正确只保证「爬虫能解析」,不保证「内容够格展示」。最常见的五个原因:一是缺 @context 或写成了 http;二是 @type 拼错或小写,整个块被静默丢弃且不报错;三是必填属性缺失(比如 Article 没 headline);四是内容与页面实际不符(比如标 Article 但页面是产品页);五是站点规模或质量没到 Google 的门槛——结构化数据是资格不是保证。建议先用富媒体测试工具看它到底读到了什么,再回头对照本页的徽标逐条查。

为什么本页不直接在我的页面上加上结构化数据?

两个原因。一是本项目模块已全站移除 application/ld+json 标签,加回去属于回退既有决策。二是本页的定位本来就是「给你自己的站点生成代码片段」——你是要粘到自己的项目里,不是粘到本页。所以本页的生成结果只以文本形式展示在结果区,「包上 script 标签」输出的是可以复制的字符串。你可以打开开发者工具的 Elements 面板确认:本页 DOM 里没有任何 ld+json 标签。

@type 到底该写 Article 还是 NewsArticle?

看内容性质而不是看网站类型。Article 是通用文章;NewsArticle 继承自 Article,多了 dateModified 与 articleSection 的语义暗示,用在新闻、公告、时效性内容上。两者必填属性完全一样(都是 headline),所以写错的后果只是「少了一些新闻类展示机会」,不会作废整个块。拿不准就用 Article,它是更宽的类型。

为什么改了标题但搜索结果还是旧的?

这是缓存与抓取周期的问题,不是代码问题。搜索蜘蛛不会实时重抓,改完结构化数据后要等下次抓取;已经进过索引的页面,展示内容还受 Google 缓存的片段控制。想看当前实际状态,去富媒体测试工具实时测,或者在搜索结果页用缓存版本对照。技术上更根本的做法是保证 dateModified 字段准确,它是蜘蛛判断内容更新时间的依据之一。

同一个实体在多个页面上怎么关联?

靠 @id。给实体一个稳定的绝对 URL 标识,比如 "@id": "https://example.com/#organization",所有页面都用这一个值,其他页面引用它时只写 {"@id": "https://example.com/#organization"} 不用重复完整信息。这样蜘蛛才能把它们合并成一个组织实体,而不是识别成几十个独立实体。关键点是这个值必须完全一致——写成 #org、写成相对路径、或者带一个多余的下划线,关联就断了。

数值和布尔值到底要不要加引号?

按 JSON 类型来:数值不加、布尔不加、字符串加。"price": 9.9 和 "available": true 是对的,"price": "9.90" 和 "available": "true" 是错的。schema.org 里很多属性明确声明为 Number 或 Boolean 类型,类型不匹配时爬虫可能直接忽略该属性——不报错,但你的价格就是展示不出来。price 写成 9.90 时 JSON 解析结果是数值 9.9(末尾 0 不保留),要保留两位小数得用字符串,那就要看该属性是否允许 Text。

JSON.stringify 的第二个参数为什么必须传 null?

因为它是 replacer(过滤器),不是缩进。传一个数组,比如 JSON.stringify(obj, ['@type', 'name']),结果里只剩这两个键,其它全被丢掉;传一个函数则会改写每个值。缩进是第三个参数。所以正确写法是 JSON.stringify(obj, null, 2)——第二个位置写 null 表示不过滤,第三个位置写 2 表示 2 空格缩进。这个签名是很多人写 JSON-LD 生成器时丢字段的根源。

我填的内容会被上传吗?

不会。全部计算由页面内的 JavaScript 完成,生成、校验、序列化都在本地,没有任何 fetch 或 XMLHttpRequest 调用,也不写 localStorage。刷新页面后表单回到默认的 Article 示例。想自己确认,打开开发者工具的 Network 面板,点「生成代码」时观察是否有请求发出——不会有。需要说明的是,你仍然要把生成结果手动粘到自己的站点,那一步发生在你自己的服务器上,不在本页范围内。

相关工具