个人网站 JSON-LD 详解
摘要
本指南介绍了如何为个人网站添加 JSON-LD 结构化数据,以提升 SEO 和获得更丰富的链接预览,涵盖基础知识和常见 Schema 类型的可复制粘贴示例。
暂无内容
查看缓存全文
缓存时间: 2026/06/22 01:33
# 为个人网站详解 JSON-LD | Ethan Hawksley 来源:https://hawksley.dev/blog/json-ld-explained-for-personal-websites/ JSON\-LD(JSON 链接数据)是一种为网页添加结构化数据的格式。它能帮助网络爬虫理解你网站的语义结构,让你获得更丰富的链接预览,甚至可能提升搜索排名。距离我上一篇描述如何构建这个网站的文章已经过去 4 个月了,根据 Wakatime 的估算,我大约花了 100 小时编码,这还不包括研究和测试的时间。此后,这个网站经历了大量打磨,包括在每个页面添加了 JSON\-LD。 ## JSON-LD 基础 要在页面中添加 JSON\-LD,请在`<head>`部分的某个位置插入以下内容: ```html <script type="application/ld+json"> { "@context": "https://schema.org", "@graph": [ { "@type": "WebSite", "@id": "https://hawksley.dev/#website", "url": "https://hawksley.dev/", "name": "Ethan Hawksley" }, // 在此处插入更多节点。 ] } </script> ``` 下面我们逐一解释每个部分的作用。 ```html <script type="application/ld+json"> ``` 这会声明一个 MIME 类型为`application/ld\+json`的新脚本。由于指定了这种类型,浏览器的 JS 引擎不会执行它。像 Googlebot 这样的专用爬虫会查找这些元素并解析其内容。 ```json { "@context": "https://schema.org" } ``` 这里初始化了一个 JSON 对象,并将`@context`属性设置为`https://schema\.org`。在 JSON\-LD 中,数据结构由分配适当的上下文来决定。网络爬虫已标准化使用 Schema\.org(在新标签页中打开)(https://schema.org/),它定义了 JSON 中所有有效的键值对。现在,既然我们已经定义了 JSON\-LD 所遵循的模式,就可以描述我们的网页了! ```json { "@graph": [ { "@type": "WebSite", "@id": "https://hawksley.dev/#website", "url": "https://hawksley.dev/", "name": "Ethan Hawksley" } // 在此处插入更多节点。 ] } ``` 一个 JSON\-LD 文档可以看作是一个带标签的有向图,存储在`@graph`中。图中包含多个节点,通过有向弧相互连接。节点具有: - `@type` - 描述节点是什么,例如`WebSite`或`SoftwareApplication` - `@id` - 节点的唯一标识符,通常是一个 URL 后跟唯一的哈希值 - 属性 - 描述节点属性的键/值对 在上面的例子中,类型是`WebSite`,ID 是`https://hawksley\.dev/\#website`,并且有两个属性:`url`和`name`。只要节点共享同一个 ID,网络爬虫就可以跨多个页面合并节点的属性。但是,仅读取单个页面的爬虫(例如 LLM)不会合并属性。当 JSON\-LD 在页面间复用时,记住平衡这一点很重要。最佳实践是让 ID 成为一个 URL 后跟一个哈希值(例如`\#website`),以唯一标识该节点。尽管 Schema\.org 上下文定义了许多类型的节点,但本指南只介绍那些对 SEO 有显著影响的节点。如果你感兴趣,可以进一步了解语义网络——这是一个很有趣的兔子洞。接下来,我们来看看网站上的每个页面应该包含哪些节点。对于每种类型,我都附上了本站的 JSON\-LD 代码,你可以直接复制粘贴并根据自己的情况进行修改。 ## WebSite 你之前已经看过`WebSite`的片段了!现在来看完整版本: ```json { "@type": "WebSite", "@id": "https://hawksley.dev/#website", "url": "https://hawksley.dev/", "name": "Ethan Hawksley", "alternateName": ["hawksley.dev", "Hawksley"], "description": "Ethan Hawksley 的个人网站和技术博客,他是一位英国计算机科学专业的学生,专注于系统编程、底层计算和网络安全。", "inLanguage": "en-GB", "publisher": { "@id": "https://hawksley.dev/#person" }, "image": { "@type": "ImageObject", "@id": "https://hawksley.dev/#website-image", "url": "https://hawksley.dev/logo-square.png", "caption": "Ethan Hawksley 标志" } } ``` `WebSite`解释了网站的元数据。它为爬虫提供了如何显示你网站的提示。Google 搜索结果中显示 hawksley.dev,网站名称 "Ethan Hawksley" 被高亮显示在此处,你可以看到 Google 将名称字段解释为域名的代表,并相应地标记了结果。尽管`WebSite`适用于每个页面,但你不必在每个页面上都包含完整版本。域名的根页面应该详细描述,但其他页面使用简化版本是完全可接受的: ```json { "@type": "WebSite", "@id": "https://hawksley.dev/#website", "url": "https://hawksley.dev/", "name": "Ethan Hawksley" } ``` 这为单页面爬虫提供了足够的上下文,使其能正确命名网站,但无需提供全部详细信息。 ## WebPage `WebPage`描述当前页面,但需要区分它与`BlogPosting`等其他类型(稍后介绍)。`WebPage`代表物理页面本身,即 HTML。它包含页面的内容。 ```json { "@type": "WebPage", "@id": "https://hawksley.dev/blog/hack-club-campfire/#webpage", "url": "https://hawksley.dev/blog/hack-club-campfire/", "isPartOf": { "@id": "https://hawksley.dev/#website" }, "name": "赢得 Hack Club Campfire 黑客马拉松", "inLanguage": "en-GB", "breadcrumb": { "@id": "https://hawksley.dev/blog/hack-club-campfire/#breadcrumb" } } ``` `WebPage`还有更具体的子类型。在这篇文章中,我会介绍`ProfilePage`和`CollectionPage`。你可以在 Schema\.org 对 WebPage 的定义(在新标签页中打开)(https://schema.org/WebPage)底部找到不太常见的类型。 ## Person 个人网站上每个页面都应该有的另一个节点是`Person`。它描述你是谁,Google 将其用作内容质量指标的一部分。越来越多的 LLM 爬虫也用它来决定在回答中引用谁。与`WebSite`不同,它的上下文足够重要,你应该在所有页面上包含它。 警告——内容较长!```json { "@type": "Person", "@id": "https://hawksley.dev/#person", "url": "https://hawksley.dev/", "name": "Ethan Hawksley", "alternateName": "ethanhawksley", "givenName": "Ethan", "familyName": "Hawksley", "description": "长描述", "disambiguatingDescription": "较短描述", "jobTitle": "计算机科学专业学生", "knowsLanguage": "en-GB", "knowsAbout": [ // 关键词 ], "nationality": { "@type": "Country", "name": "United Kingdom" }, "homeLocation": { "@type": "Place", "address": { "@type": "PostalAddress", "addressCountry": "GB" } }, "affiliation": { "@type": "HighSchool", "url": "https://www.alcestergs.co.uk", "name": "Alcester Grammar School", "sameAs": [ "https://www.wikidata.org/wiki/Q4713005", "https://en.wikipedia.org/wiki/Alcester_Grammar_School" ] }, "alumniOf": [ { "@type": "HighSchool", "url": "https://www.brookeweston.org", "name": "Brooke Weston Academy", "sameAs": [ "https://www.wikidata.org/wiki/Q4974495", "https://en.wikipedia.org/wiki/Brooke_Weston_Academy" ] } ], "image": { "@type": "ImageObject", "@id": "https://hawksley.dev/#person-image", "url": "https://hawksley.dev/ethan-hawksley.png", "caption": "Ethan Hawksley", "width": 1200, "height": 1200 }, "sameAs": [ "https://github.com/ethan-hawksley", "https://www.linkedin.com/in/ethanhawksley", "https://lobste.rs/~ethanhawksley", "https://news.ycombinator.com/user?id=ethanhawksley" // 等等 ] } ``` 哇!`Person`有很多属性。我发现,在填写时,描述得更多比更少更好。让我们看看最重要的属性: - `url` - 指向你的根页面,锚定节点。 - `name`、`givenName`、`familyName` - 清晰描述你的姓名。 - `image` - 最好是你的照片,或者与你关联的标志。将你与规范化的图片连接起来。 - `sameAs` - 对于消除歧义非常有用,尤其是如果你的名字很常见。它能清晰地告知爬虫你的其他个人资料是什么,让它们构建跨多个页面的知识图谱表示。在撰写本文时,/g/11m62cgdtf(在新标签页中打开)(https://www.google.com/search?kgmid=/g/11m62cgdtf)是我 Google 知识图谱的 ID。`Person`的其他属性对于添加更多细节很有用,但并非严格必要。你可以根据需要裁剪它们,影响很小。 ## ProfilePage 正如你可能预期的,`ProfilePage`描述网站上关于某个人的页面。例如,我在我的首页上使用这个节点,因为我在那里介绍自己。在你的网站上,将其放在关于页面可能更合适。 ```json { "@type": "ProfilePage", "@id": "https://hawksley.dev/#webpage", "url": "https://hawksley.dev/", "isPartOf": { "@id": "https://hawksley.dev/#website" }, "name": "关于 Ethan Hawksley", "inLanguage": "en-GB", "dateCreated": "2024-09-10T00:00:00.000Z", "dateModified": "2026-05-17T00:00:00.000Z", "mainEntity": { "@id": "https://hawksley.dev/#person" } } ``` 使用`isPartOf`将其链接到你更广泛的`WebSite`节点,以在两个节点之间创建关系,这一点很重要。`mainEntity`也是如此,它让爬虫知道页面是关于谁的。包含`dateCreated`和`dateModified`是向爬虫传递新鲜度信号的好方法,但如果你的网站没有现成的这些信息,也不必过于担心。 ## SoftwareApplication 如果你在页面上展示任何软件,最好包含一个`SoftwareApplication`节点来描述其元数据。 ```json { "@type": "SoftwareApplication", "@id": "https://hawksley.dev/#project-yt-play", "url": "https://crates.io/crates/yt-play", "name": "yt-play", "description": "一个用 Rust 编写的 CLI 工具,用于将 YouTube 播放列表同步到本地目录。", "applicationCategory": "MultimediaApplication", "operatingSystem": "All", "creator": { "@id": "https://hawksley.dev/#person" }, "sameAs": ["https://github.com/ethan-hawksley/yt-play"], "offers": { "@type": "Offer", "price": 0, "priceCurrency": "GBP" } } ``` 如果你想比`SoftwareApplication`更具体,其他有效的节点类型包括`MobileApplication`、`WebApplication`和`VideoGame`。`url`属性应该是项目部署位置的链接,例如 crates.io。`sameAs`用于与项目相关的任何其他页面,例如其源代码仓库。`applicationCategory`有很多有效值,你可以在 Google 对 SoftwareApplication 的定义(在新标签页中打开)(https://developers.google.com/search/docs/appearance/structured-data/software-app)中找到列表。即使你的项目是 FOSS,也要包含`offers`,但确保将价格设置为 0。 ## BreadcrumbList `BreadcrumbList`非常有用,应包含在所有页面中(根页面除外)。它用于描述页面的分类,不一定是页面的实际路径。 ```json { "@type": "BreadcrumbList", "@id": "https://hawksley.dev/blog/hack-club-shipwrecked/#breadcrumb", "itemListElement": [ { "@type": "ListItem", "item": "https://hawksley.dev/", "position": 1, "name": "首页" }, { "@type": "ListItem", "item": "https://hawksley.dev/blog/", "position": 2, "name": "博客" }, { "@type": "ListItem", "item": "https://hawksley.dev/blog/hack-club-shipwrecked/", "position": 3, "name": "Hack Club 的 Shipwrecked 黑客马拉松" } ] } ``` `BreadcrumbList`描述页面的路径。通过包含一个,你可以控制搜索引擎如何表示特定页面的路径。Google 搜索结果中显示 "The Shipwrecked Hackathon by Hack Club",面包屑被高亮显示在此处,我的博客文章的搜索结果包含路径`https://hawksley\.dev › Blog`。如果你的网站已经使用短路径,这个节点带来的增益很小,可以省略。但是,如果你的路径较长,`BreadcrumbList`对于缩短它们很有用。 ## CollectionPage `CollectionPage`节点是`WebPage`的子类型,可用于主要包含列表的页面。例如,我的 /elsewhere/ 页面列出了我所有的其他个人资料,/blog/ 页面列出了我所有的博客文章。 ```json { "@type": "CollectionPage", "@id": "https://hawksley.dev/elsewhere/#webpage", "url": "https://hawksley.dev/elsewhere/", "isPartOf": { "@id": "https://hawksley.dev/#website" }, "name": "其他地方", "description": "Ethan Hawksley 的在线个人资料,他是一位英国计算机科学专业学生。链接包括他的开发、社交媒体、技术写作和安全账户。", "inLanguage": "en-GB", "about": { "@id": "https://hawksley.dev/#person" }, "breadcrumb": { "@id": "https://hawksley.dev/elsewhere/#breadcrumb" } } ``` 你已经见过其中大部分属性,因此它们基本不言自明。确保将`breadcrumb`链接到正确的`BreadcrumbList`!它必须是当前页面上的那个,才会有意义。 ## Blog 你应该将`Blog`节点添加到博客的索引页或首页。它在你的`WebSite`和你发布的单篇博客文章之间起到桥梁作用。 ```json { "@type": "Blog", "@id": "https://hawksley.dev/blog/#blog", "isPartOf": { "@id": "https://hawksley.dev/#website" }, "mainEntityOfPage": { "@id": "https://hawksley.dev/blog/#webpage" }, "name": "Ethan Hawksley 的博客", "description": "Ethan Hawksley 的技术博客,他是一位英国计算机科学专业学生。文章涵盖系统编程、底层计算、网络安全和计算机科学。", "inLanguage": "en-GB", "dateModified": "2026-05-17T00:00:00.000Z", "publisher": { "@id": "https://hawksley.dev/#person" }, "license": "https://creativecommons.org/licenses/by/4.0/" } ``` `dateModified`是一个很好的新鲜度信号,但如果你不方便获取,也不必担心。包含`license`让爬虫知道它们可以在什么情况下使用你的文章。 publisher 属性的定义,可用类型包括 Organization 和 Person 如果你之前研究过 JSON\-LD,可能会对`publisher`属性设置为`Person`(而非`Organization`)感到惊讶。虽然以前要求是 Organization,但 Google 的文档后来已经放宽,`Person`也完全有效,而且对于个人网站来说,可能更准确。 ## BlogPosting 我们要讨论的最后一个节点是`BlogPosting`。它应包含在所有已发布的博客文章中,为爬虫提供更多信息,使其能够更准确地呈现它们,包括在搜索结果中获得更准确的定位和更丰富的细节。 ```json { "@type": "BlogPosting", "@id": "https://hawksley.dev/blog/need-for-post-quantum-cryptography/#blogposting", "url": "https://hawksley.dev/blog/need-for-post-quantum-cryptography/", "mainEntityOfPage": { "@id": "https://hawksley.dev/blog/need-for-post-quantum-cryptography/#webpage" }, "isPartOf": { "@id": "https://hawksley.dev/blog/#blog" }, "headline": "后量子密码学的必要性", "description": "量子计算机比我们想象的更接近破解 RSA 和 ECC。了解什么是后量子密码学以及如何开始迁移。", "articleSection": "网络安全", "keywords": "网络安全, 量子", "inLanguage": "en-GB", "datePublished": "2026-04-13T00:00:00.000Z", "dateModified": "2026-04-17T00:00:00.000Z", "author": { "@id": "https://hawksley.dev/#person" }, "publisher": { "@id": "https://hawksley.dev/#person" }, "image": { "@type": "ImageObject", "@id": "https://hawksley.dev/blog/need-for-post-quantum-cryptography/#blogposting-image", "url": "https://hawksley.dev/og/blog/need-for-post-quantum-cryptography.png", "width": 1200, "height": 630 }, "license": "https://creativecommons.org/licenses/by/4.0/" } ``` 由于这是个人网站,`author`和`publisher`都指向同一个`Person`节点是可以的。`image`属性应与该文章已经在使用的 OG 图片一致,用于链接预览。 ## 结论 恭喜,这就是个人网站需要的全部 JSON\-LD!我这样组织这篇文章,是为了让你能够尽可能轻松地复制粘贴并实现到你自己的个人网站上。即使你运行的是没有构建步骤的静态网站,添加至少一部分这些节点仍然能带来好处。
相似文章
LLM如何决定引用哪些页面——以及如何优化
本文阐述了 ChatGPT 和 Perplexity 等模型如何选择引用来源,并指出结构化标记(JSON-LD)能够通过提升信息提取效率,将引用率从 16% 大幅跃升至 54%。
用机器重建我的博客,为机器服务·
作者重建了博客,加入了完整的结构化数据标记(JSON-LD、微格式),并配备了一个由提示词引导的AI协作写作助手,该提示词避免了常见的LLM模式,同时通过CI验证防止数据损坏。
关于 <dl> 元素
一份详细指南,介绍如何使用 HTML 的 <dl>、<dt> 和 <dd> 元素以语义化方式标记名称-值对,并附有示例。
网站检查清单
一份全面的现代网站构建检查清单,涵盖HTML基础、SEO、无障碍性等,内容来源于网站规范。
google-labs-code/design.md
DESIGN.md 是来自 Google Labs 的格式规范,它将 YAML 设计令牌与 Markdown 文本相结合,为编码代理提供对设计系统的结构化理解,包括 lint 工具和 diff 比较。