关闭

Tryaivo™技术

8 个公开数据页只有 1 个写了 Dataset 标记

2026-11-12 03:17:26 浏览:

结论先说:本机 2026-11-12 抽查 8 个公开数据页(世界银行 2 个指标页、data.gov.uk 1 个数据集页、datahub.io 2 个、Our World in Data 2 个、Statista 1 个),只有 Statista 输出了 Dataset 节点,而且缺 10 个推荐字段里的 10 个。抓取器不看图、不看 API,只认服务端 HTML 里的 JSON-LD。

背景:数据站把力气全花在图和 API 上了

做数据站的人有共识:数据要好取,就得有 API、有 CSV、有可交互可视化。所以这些年数据站的工程投入几乎全在 API 与图表上,结构化标记这块基本是空白。

但"取数"的入口在变。Google Dataset 搜索读的是 schema.org/Dataset;越来越多的 AI 代理在抓一个站点前先看有没有 Dataset / DataDownload 节点,能拿到 contentUrl 就直连下载,拿不到就去解析图表页——那是成本最高的路径,也是最容易读错的路径。

于是出现一个很典型的错位:页面人看着清清楚楚,机器读到的是一片空白。

这篇文章不讲"应该打标记"这种大道理,只给三样东西:可抄的字段清单、可跑的校验脚本、以及一次真实的线上抽样。

落地清单

一、字段清单(按 Google Dataset 文档口径)

级别字段说明
必填name数据集名称
必填description摘要,长度 50–5000 字符
推荐identifier稳定的 ID(URN/UUID/DOI 均可)
推荐url数据集落地页
推荐sameAs同一数据集的其它公开地址(JSON/CSV/DOI)
推荐creator / funder出品方 / 资助方,用 Organization 节点
推荐license许可 URL,别写"CC BY 4.0"这种纯文本
推荐distribution下载入口,含 contentUrl + encodingFormat
推荐keywords关键词数组
推荐variableMeasured数据集里的列,用 PropertyValue 数组
推荐measurementTechnique测量/采集方法
推荐spatialCoverage / temporalCoverage空间/时间覆盖,时间用 ISO 8601 区间
推荐includedInDataCatalog所属目录,DataCatalog 节点
推荐isAccessibleForFree是否免费公开,必须与真实访问状态一致
推荐version / citation版本号 / 引用方式

口径说明:上表按 Google Dataset 结构化数据文档整理,具体条目经 galaxyproject/brc-analytics 的 issue #1264(2026-05-06)逐条转述;本机 2026-11-12 直连 developers.google.com 超时,未能对原文做二次核对,引用时请注意这一层。

二、真实落地参考:BRC Analytics 的做法

那个 issue 里最有价值的不是字段表,而是实施路径:

  • 用一个 buildDatasetJsonLd() 工厂函数集中产出对象,页面组件只负责传参——避免每个页面各写一份 JSON;
  • 注入走框架的 head 机制,并对注入的字符串做 HTML 转义(<、>、& 必须转),否则摘要里出现尖括号就会把 script 标签提前闭合;
  • 写单测断言三件事:必填字段存在、超长 description 被截断到 5000 以内、可选字段缺失时不输出空字段;
  • 上线后用 Rich Results Test 逐页验证,再到 Search Console 请求重新索引。

三、可抄的完整 JSON-LD

下面这段是可直接替换的模板(本人站点占位,字段一个不缺):

{
  "@context": "https://schema.org",
  "@type": "Dataset",
  "@id": "https://www.example.com/dataset/ai-citation-audit-2026q4#dataset",
  "name": "GEO 站点 AI 可引用性抽样数据集(2026 Q4)",
  "description": "对 120 个技术类站点 llms.txt 与 JSON-LD 落地情况的抽样结果,字段包含站点域名、llms.txt 状态码、Content-Type、文件体积、Markdown 兄弟文件数量、是否含可执行安装指令、Dataset 标记字段覆盖率,用于观察 AI 代理取数时的结构化暴露差异。抽样时间 2026-10-01 至 2026-11-01。",
  "url": "https://www.example.com/dataset/ai-citation-audit-2026q4",
  "identifier": "urn:uuid:6f1d2c9a-7b34-4a1e-9c58-2d0e5b7a1f43",
  "sameAs": ["https://www.example.com/dataset/ai-citation-audit-2026q4.json"],
  "creator": { "@type": "Organization", "name": "example.com", "url": "https://www.example.com/", "sameAs": ["https://www.example.com/about"] },
  "funder": { "@type": "Organization", "name": "example.com", "url": "https://www.example.com/" },
  "license": "https://creativecommons.org/licenses/by/4.0/",
  "isAccessibleForFree": true,
  "keywords": ["llms.txt", "JSON-LD", "GEO", "AI 可见度", "结构化数据"],
  "version": "2026.11",
  "temporalCoverage": "2026-10-01/2026-11-01",
  "spatialCoverage": { "@type": "Place", "name": "全球" },
  "measurementTechnique": "HTTP GET 直取 + 正则提取 application/ld+json + 字段存在性判定",
  "variableMeasured": [
    { "@type": "PropertyValue", "name": "llms_txt_status_code", "unitText": "HTTP status" },
    { "@type": "PropertyValue", "name": "llms_txt_bytes", "unitText": "byte" },
    { "@type": "PropertyValue", "name": "markdown_sibling_count", "unitText": "count" },
    { "@type": "PropertyValue", "name": "dataset_field_coverage", "unitText": "percent" }
  ],
  "distribution": [
    { "@type": "DataDownload", "name": "CSV 明细", "contentUrl": "https://www.example.com/dataset/ai-citation-audit-2026q4.csv", "encodingFormat": "text/csv" }
  ],
  "includedInDataCatalog": { "@type": "DataCatalog", "name": "example 开放数据目录", "url": "https://www.example.com/dataset/" },
  "citation": "example.com, GEO 站点 AI 可引用性抽样数据集(2026 Q4), 2026-11-12"
}

四个容易写错的地方:license 必须是 URL;temporalCoverage 必须是 YYYY-MM-DD/YYYY-MM-DD 而不是"从几月到几月";distribution 必须带 encodingFormat,否则下载入口等于没声明格式;@id 给 Dataset 单独一个锚,别复用页面的锚。

四、注入位置:必须在服务端 HTML 里

这是整篇最硬的一条。JSON-LD 要出现在服务端返回的 HTML 源码里,而不是等客户端水合后才生成。校验命令就一行:

curl -s https://example.com/dataset/xxx | grep -c 'application/ld+json'

返回 0 就是没落地——不管前端看着多正常。

五、本机校验脚本的真实输出

我写了一个 60 行的本地校验器(检查 @type、必填、description 长度区间、distribution 必填项、license 是否为 URL、temporalCoverage 是否 ISO、isAccessibleForFree 风险提示),对上面的模板和两个真实页面跑出来的结果:

[模板] ERROR 0 / WARN 1 / 缺推荐 0
  W: isAccessibleForFree=true:确认页面无登录/订阅墙
[statista] HTML 386523 B / JSON-LD 块 1
  块0: Dataset -> ERROR 0 / WARN 1 / 缺推荐 10
    W: temporalCoverage 非 ISO 8601: From 01/01/2026 to 31/12/2026
    缺推荐: identifier,sameAs,funder,license,distribution,variableMeasured,measurementTechnique,isAccessibleForFree,version,citation
[datahub.io/core/gdp] HTML 102478 B / JSON-LD 块 0
  -> 页面无 Dataset 节点(沉默失败)

注意 Statista 那行的 ERROR 0:它在 Google 眼里是"合格"的——必填只有 name 和 description,两个都在。缺的 10 个全是推荐字段,所以不会报错,也不会被处罚,只会静默地少拿到东西。这就是 Dataset 标记最容易"沉默失败"的原因。

结果:8 个公开数据页的线上抽样(本机 2026-11-12)

页面HTML 字节JSON-LD 块@type 概况Dataset
data.gov.uk/dataset/uk-public-procurement-notices-april-2021249,2520全文连 schema.org 字符串都是 0 次无
data.worldbank.org/indicator/SP.POP.TOTL786,8080—无
data.worldbank.org/indicator/NY.GDP.MKTP.CD1,278,0120—无
datahub.io/core/gdp102,4780(仅 RSC 流式负载里有组件描述)—无
datahub.io/collections110,9330—无
ourworldindata.org/grapher/life-expectancy120,5321WebPage + ImageObject + Organization无
ourworldindata.org259,3310—无
statista.com/statistics/262955/largest-countries-in-the-world386,5231WebPage + BreadcrumbList + Article + Dataset + DataCatalog + Place有

几点值得单独说:

1. data.gov.uk 的数据集页连 schema.org 都没提过。 49,252 字节的 HTML 里 schema.org 出现 0 次。这是国家级开放数据门户的数据集详情页——人能找到、API 能取,但结构化层面对爬虫是空白。

2. datahub.io 把 JSON-LD 写在 RSC 流式负载里,没落到 HTML。 102,478 字节的 HTML 里 application/ld+json 只以 React Server Component 的组件描述形式出现({"id":"json-ld-datapackage","type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"$23"}}),全文检索 Dataset 字符串 0 次,也没有真实的 <script type="application/ld+json"> 标签。也就是说:代码里写了,用户浏览器里能看到,但服务端 HTML 里没有。 不执行 JS 的抓取器一律看不到。

3. Our World in Data 的图表页有 JSON-LD,但不是 Dataset。 1 个块,WebPage + ImageObject + Organization。图表页是最典型的"数据就在页面上"的形态,却完全没有 Dataset 声明。

4. Statista 那一份是样本里唯一合格的,结构是:页面级对象 → hasPart → Dataset,Dataset 里再挂 creator(Statista Research Department)、includedInDataCatalog(International)、keywords(10 个)、spatialCoverage(Place: Worldwide)、temporalCoverage("From 01/01/2026 to 31/12/2026")。

它的三个问题同样典型:

  • temporalCoverage 用了人类可读写法而非 ISO 8601;
  • Dataset 节点自身没有 isAccessibleForFree,而页面级的 isAccessibleForFree: true 挂在外层对象上,同时该页 HTML 里 premium 字样出现 8 次(完整数据需订阅)——声明与真实可访问性对不上,这是红线级问题;
  • license、distribution 全缺,等于告诉爬虫"这是数据集"但没告诉它"去哪下、按什么许可用"。

复盘:3 条配置动作 + 2 条红线

能直接抄的 3 条

  • 最小可用集先上:name、description、url、creator、license、distribution。这六个字段决定"能不能被识别 + 能不能被下载 + 能不能被合规引用",比堆 20 个字段有用。
  • 用工厂函数 + 单测锁死格式:description 自动截断到 5000、temporalCoverage 强制 ISO 区间、license 强制 URL 校验,缺一个字段就让测试挂掉。
  • 上线用两把尺子量:curl | grep -c 'application/ld+json' 验证"落没落到 HTML",本地校验器验证"字段对不对"。两个都过才算完成。

2 条红线(含一条"别这么做")

  • 别给订阅墙 / 登录墙后的数据打 isAccessibleForFree: true。 免费标签会让人和代理都以为能直接拿,实际拿到 403 或付费页——这类不一致比不写标记更糟,因为它消耗的是信任。
  • 别把"页面对象"当 Dataset。 把 Dataset 塞进 WebPage.hasPart 能解析,但没独立 @id 就很难被单独引用和去重;至少要给 Dataset 自己的 @id 与 url,让它成为一个可以被指名的实体。

标注

  • Schema.org 版本:现行版,查询于 2026-11-12。本机该时段 schema.org 直连超时,未取到具体版本号;最近一次已知版本为 v30.1(2026-09-16 发布)。
  • 字段清单来源:Google Dataset 结构化数据文档,经 galaxyproject/brc-analytics issue #1264(2026-05-06)转述,developers.google.com 本机不可达,未做原文二次核对。
  • 验证工具与时间:本机 Python 校验器(2026-11-12,输出见上文)+ curl/PowerShell 直取原始 HTML 计数;Google Rich Results Test 与 Schema Markup Validator 在本机网络环境下无法访问,未执行,本文所有"通过/未通过"结论均指本地校验结果,不代表 Google 侧验证结果。
  • 抽样数据口径:2026-11-12 本机 HTTP GET 直取原始未压缩 HTML,字节数为响应体长度;JSON-LD 块数按 <script type="application/ld+json"> 字面计数,用正则逐块 json.loads 复核。
  • 本文无 CTR、曝光、AI 引用次数数据,不做效果承诺。