使用方法
- 在第一个下拉框里选 schema.org 类型。类型一旦选定,下方必填与推荐属性会跟着切换——
Article要headline,Organization要name,WebSite要name加url。页面打开时默认是Article,标题框里已经预置了「如何写好一份结构化数据」。 - 填标题和页面 URL。URL 必须以
https://开头:schema.org 的url与@id都按绝对 URL 处理,写成/post/1这种站点内相对路径在富媒体测试里会被判为无效。 - 点「生成代码」(结果区是即时更新的,改完字段就会重出片段)。输出默认是 2 空格缩进,方便肉眼核对;想贴成一行,点「包上 script 标签」会同时给出可直接粘进
<head>的完整三行形式。 - 看结果区下方的徽标行。绿色的表示通过,红色的每一条都写清了哪个字段、允许什么格式——这些是
JSON.parse发现不了的错误:类型名拼错、日期写成2026/10/03、@id写成#org,这三类在 JSON 语法上完全合法,只有按 schema.org 规则逐条查才能揪出来。 - 点「复制片段」把代码带走,粘到
<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 | 文章 | headline | author / datePublished / image |
| NewsArticle | 新闻 | headline | dateModified / articleSection |
| Organization | 组织机构 | name | url / logo / sameAs / legalName |
| Product | 商品 | name | offers.price / priceCurrency / availability |
| FAQPage | 问答页 | mainEntity | Question.acceptedAnswer.text |
| BreadcrumbList | 面包屑 | itemListElement | ListItem.position / name / item |
| WebSite | 网站首页 | name / url | potentialAction → SearchAction |
| LocalBusiness | 本地商家 | name / address | telephone / geo / openingHours / priceRange |
| Recipe | 菜谱 | name | recipeIngredient / recipeInstructions / prepTime |
| SoftwareApplication | 应用 | name | applicationCategory / operatingSystem |
| VideoObject | 视频 | name / description / thumbnailUrl | uploadDate / duration / contentUrl |
| Person | 人物 | name | url / 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 面板,点「生成代码」时观察是否有请求发出——不会有。需要说明的是,你仍然要把生成结果手动粘到自己的站点,那一步发生在你自己的服务器上,不在本页范围内。
相关工具
- Meta标签生成器:产出
<meta>标签,与 JSON-LD 配合影响同一批搜索结果字段。 - Open Graph Meta标签生成器:补齐社交分享卡片,JSON-LD 管搜索摘要、OG 管分享预览。
- XML站点地图生成器:另一条让爬虫认识你的入口,与结构化数据互补而非替代。
- Robots.txt生成器:控制抓取范围,结构化数据再全,被 robots 拦下也没用。
- JSON美化打印:把已有片段排版整齐,方便逐行核对字段名。
- JSON校验工具:只做第一层 JSON 语法校验,与本页的第二层规则校验互补。
- 开发者工具:查看全部开发者工具。