一文读懂HTML微数据

456 阅读8分钟

本文为HTML标准解读系列文章,其他文章详见这里

关于微数据,我们可以先从一个简单的HTML片段入手:

<h1>对象</h1>

不同的人看到“对象”有可能会理解成不同的意思:普通人会理解为自己的恋人,程序员为理解为一个编程概念,象棋爱好者会想到棋谱中的两颗棋子。不过,只要有上下文,我们就能消除歧义:

<h1>对象</h1>
<p>姓名:如花</p>
<p>身高:155cm</p>
<p>体重:130kg</p>

然而,即便配合上下文,对于机器(如搜索引擎)来说,依旧没有足够的智能推断出这里的对象究竟指的是哪一种意思。这时,就是「微数据」派上用场的地方:

<div itemscope itemtype="https://schema.org/Person">
    <h1>对象</h1>
    <p>姓名:<span itemprop="name">如花</span></p>
    <p>身高:<span itemprop="height">155 cm</span></p>
    <p>体重:<span itemprop="weight">130 kg</span></p>
</div>      

在这里:itemscope表示这是一个微数据的项,itemtype表示这个项的类型,itemprop表示这个项的属性。对于这个HTML片段,搜索引擎可以提取出以下的数据:

{
	"@type": "Person",
	"name": "如花",
	"height": "155 cm",
	"weight": "130 kg",
}

这种被提取出来的数据也称为「结构化数据 structured data」。 有了这些数据,搜索引擎就能准确理解页面的内容,并给页面建立更加精细的分类。以后,别人搜“恐龙”或者“坦克”的时候,你的对象如花就可能就会出现在搜索结果里头了。

当然,这只是一个玩笑。不过,利用结构化数据除了能提高搜索结果的准确率,还能让搜索的结果以更加有意义的方式呈现。比如,当我在谷歌搜“可乐鸡翅”时,会有这样的结果:

recipe_example

这里每一份食谱的封面、标题、数据都是谷歌通过提取页面内的结构化数据再作呈现的。对于使用者来说,我不仅能够提前看到每一份食谱的评分、视频时长等数据,我甚至还能基于这些维度对食谱进行过滤。

除了食谱以外,基于结构化数据的其他类型的特殊呈现,你可以在这个谷歌开发文档中看到。

微数据的使用

在微数据模型中,一个页面的结构化数据是由多个「项」组成的;每一个项含有的信息可能包括:项类型、全局标识符以及多个属性。 (微数据中的“属性”与HTML的“属性”是两个不同的概念,为了在本文进行区分,HTML的“属性”都会使用「HTML属性」命名,微数据的“属性”会继续使用「属性」)

与微数据相关的所有HTML属性如下所示,它们属于全局HTML属性,是所有元素都共享的:

  • itemscope:创建一个新的项。
  • itemtype:定义项类型。
  • itemprop:添加一个属性到项中。
  • itemid:声明项的全局标识符。
  • itemref:关联不在项元素子代的属性。

一个属性的值即可以是一个字符串,也可以是一个新的项。如以下这个例子,“净资产”一栏就是嵌套的项。

<div itemscope itemtype="https://schema.org/Person">
    <h1>对象</h1>
  	<p>姓名:<span itemprop="name">如花</span></p>
    <p>身高:<span itemprop="height">155 cm</span></p>
    <p>体重:<span itemprop="weight">130 kg</span></p>
    <p>净资产:<span itemprop="netWorth" itemscope itemtype="https://schema.org/MonetaryAmount">
        <span itemprop="value">30,000,000</span> <span itemprop="currency">USD</span>
    </p>
</div> 

itemtype与词汇表

在开篇的例子中我们可以看出,结构化数据是给机器而不是人类阅读的。因此,我们必须使用机器能够理解的“词汇”。一些社区会制定各种各样的「词汇表(vocabularies)」,规范在结构化数据中描述不同事物的不同方面的用词,这些词汇表就是开发者与搜索引擎对于描述事物用词的协议。 一张词汇表通常会带有以下信息:

  • 词汇表所描述内容的范围。比如有的词汇表是用来描述人的,有的词汇表用来描述一个事件的。
  • 词汇表的权威URL,这个URL会用在itemtype上,表明一个项所使用的词汇表。
  • 词汇表的属性列表,包括每一个属性的命名、预期类型、具体含义,这些属性会用在itemprop 上;
  • 词汇表的全局标识符,只有特定的词汇表才支持全局标识符,对应itemid,具体会在后面讲到。

以一张上面例子中用到的词汇表Person为例,下面截取了这张词汇表中我们使用到的部分:

Person:

描述:一个人(活的、死的、不死的、虚构的)。

权威URL:schema.org/Person。

属性(Property)预期类型(Expected Type)描述(Description)(简化版本)
name文本表示该项的名字。
weight可量化的值表示该项的重量。
height距离/可量化的值表示该项的高度。
netWorth金钱数量/价格的值一个人的资产减去负债。
.........

在预期类型中,可量化的值、距离、金钱数量、价格的值,都是进一步细分的词汇表。出于简洁的原因,我在上面例子中的身高、体重属性并没有使用嵌套的项。

比较有名的词汇表集合是Schema.org,它是由各大知名的搜索引擎共同开发并实际应用的。我在上面的例子中,就是使用了两张里面的词汇表:Person以及金钱数量

当你使用Schema.org的词汇表,你可以通过它提供语法检查工具,查看你页面中的微数据语法是否合法,以及提取出来的结构化数据。

validator

itemprop与属性值的提取规则

一般来说,微数据属性会提取元素后代的文本内容作为它的值,比如下面这个name属性,值为“如花”。

<p>姓名:<span itemprop="name">如花</span></p>

但是对于一些特殊的元素,值的提取会使用其他的规则,比如下面例子的image属性,会提取HTML属性src作为它的值;而url属性,会提取HTML属性href作为它的值。

<p><img itemprop="image" src="https://XXX.com/profile" alt="正面照">
<p><a itemprop="url" href="https://XXX.com/page">个人主页</a>

所有的特殊情况如下所示:

  • 如果元素有HTML属性itemscope,会创建一个新的项。
  • 对于meta元素,会使用HTML属性content作为值。
  • 对于audioembediframeimgsourcetrack video元素,会使用HTML属性src作为值。
  • 对于aarealink元素,会使用HTML属性 href作为值。。
  • 对于object元素,会使用HTML属性data作为值。
  • 对于datameta元素,会使用HTML属性value作为值。
  • 对于time元素,会使用它的datatime作为值。

更多的细节可以查看标准关于微数据值的处理模型

itemid与全局标识符

在这个世界上,有一些事物是有自己独一无二的标识的。比如每一本正规出版的书籍,都会有自己对应的isbn号码,无论在任何场景下,使用这个isbn号码就能毫无偏差地指代这一本书。所以,可以说isbn号码就是一本书的“全局标识符”

如果一张词汇表描述的事物也具有类似这样“全局标识符”的特点,那这张词汇表也许就支持全局标识符(具体取决于词汇表的定义)。在微数据中,全局标识符使用HTML属性itemid表示。比如以下的例子中,使用itemid表明这个项在谈论一本特定的书:

<dl itemscope
    itemtype="https://vocab.example.net/book"
    itemid="urn:isbn:9789574706396">
 <dt>标题
 <dd itemprop="title">會撒嬌的女人最好命
 <dt>作者
 <dd itemprop="author">羅夫曼
</dl>

需要注意的,带有HTML属性itemid的元素必须同时带有HTML属性itemtypeitemscope,且不应该在不支持全局标识符的词汇表中使用itemid

itemref

itemref 用于关联那些不在项元素子代的属性,itemref会爬取页面内对应id的元素,把这些元素内的微数据属性添加到项中。如以下例子,a属性会被添加到项中。

<div id="x">
 <p itemprop="a">1</p>
</div>
<div itemscope itemref="x">
 <p itemprop="b">2</p>
</div>

itemref常用在不方便把属性放在项元素子代的情况。

结构化数据的其他格式

微数据只是搜索引擎可用于提取页面中结构化数据的其中一种格式,其他常用的格式还包括:

  • JSON-LD:使用一个json直接表示页面中的结构化数据,在一个type="application/ld+json"的script标签中声明。如:

    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Person",
    	"identifier": "对象",
      "height": "155 cm",
      "weight": "130 kg"
    }
    </script>
    
  • RDFa:使用XML相关属性表示页面中的结构化数据。如:

    <div vocab="https://schema.org/" typeof="Person">
        <h1 property="identifier">对象</h1>
        <p>身高:<span property="height">155 cm</span></p>
        <p>体重:<span property="weight">130 kg</span></p>
    </div>   
    
  • Microformat:使用HTML属性class表示页面中的结构化数据。

根据谷歌的开发文档,谷歌搜索支持JSON-LD微数据 以及 RDFa 这3种格式,但推荐开发者使用JSON-LD,大概是因为JSON-LD是最简洁的。幸运的是,这三种格式所使用的词汇表大多都是共享的,比如每一张Schema.org的词汇表都可以同时编码成这三种格式,且每张词汇表的下面都给我们列举了同一结构化数据下这3种格式的例子。