如何从 WEB 页面中提取信息

已经五个月没有更新 blog 了,这五个月全身心投入到了两个关于如何从页面上抽取结构化数据的项目上。这也是我加入某厂最主要的原因。其中一个全自动模板生成抽取器,虽然还不完全能够实用,但比1年前效果好太多,同时也让我想明白了一些问题。这都是下文主要讨论的问题。

关于 pyspider 项目,这几天我也在慢慢填上这延期了3个月的坑,至少完成第二里程碑吧。但缺少实际应用的环境,很多东西是否工作得很好,我也不是很有把握。如果有的话,还是希望支持1-2个实际的抓取项目吧。

而 “如何获得页面/数据” 这个问题依旧是我持续关注中,想要去解决的问题。但是,既然某厂的后续解决方案是将所有抓取页面过 webkit 渲染(虽然很多时候渲染不出 或 需要点击动作,代价往往大于直接抓 API),不会有很多精力投入,待我慢慢想想。。

##四种解析模式

xpath / css选择器 / 正则表达式

示例: https://www.kimonolabs.com/

通过手动、自动、半自动方式,设定需要抽取元素的 xpathcss选择器 或 正则表达式 进行定位提取的方法(这里需要指出的是,html 并不是正则的,正则表达式可能在部分简单提取时有效,但 不要用正则表达式进行页面提取)。其根本思想是提供一种定位元素的规则进行页面抽取。

这个方法被用得最多,好处是有效,嗯。缺陷在于用户需要会 xpath / css选择器 / 正则语法,虽然有一些工具(例如上面的kimono、chrome的调试工具、pyspider里面的脚本)辅助生成规则,但可能通用性不足 或 区分度不够,选取到不需要的内容。这在大批量抽取时需要大量的高级人力去配置,即使是熟练工也需要5-10分钟配置一个页面(6-8个属性),需要耗费大量精力。

这种抽取方式的一种变形是:将 key 和 value 同时在页面中标出,通过 key 和 value 总是穿插出现的这一假设,省去单独为每个属性设置规则的人力,极大增快标注效率。
例如:http://movie.douban.com/subject/7054604/ 这个页面中的

导演: 迈克尔·贝
编剧: 伊伦·克鲁格
主演: 马克·沃尔伯格…
类型: 动作 / 科幻 / 冒险
制片国家/地区: 美国 / 中国大陆
语言: 英语 / 汉语普通话 / 粤语
上映日期: 2014-06-27(美国/中国大陆)
片长: 166分钟
又名: 变形金刚:歼灭世纪(港) / 变形金刚4:灭绝时代 / 变形金刚4 / 变4 / Transformers 4
IMDb链接: tt2109248

导演/编剧/类型等 属性名 往往拥有相同的 xpath,而值的 xpath 也是独立的几种。他们一定是 key: value 的形式组织的,通过用 key 分割 value 的方式能轻松将所有信息提取出来。

data highlighter

示例: http://googlewebmastercentral.blogspot.com/2012/12/introducing-data-highlighter-for-event.html

Data Highlighter 的标注方式是:给一系列相似的页面,让用户标出(高亮)每个属性在页面中的位置。通过多个页面的标注信息,寻找每个属性的特征。当然了,这个特征可以是 xpath,也可以是上下文,也有可能是机器学习的特征向量。

Data Hightlighter 通过高亮 多个页面中相同属性 进行规则学习,省去了人为设置规则时的学习成本。实践表明,在单一页面模板下,标记2个页面就足以生成规则了。效率远大于手工设置规则。Google Data Highlighter 甚至对文字进行了切分,能在 英语 / 汉语普通话 / 粤语 xpath 相同的情况下,分别选出三种语言。是我目前见过的成熟度最高、通用性最好、最简便的数据抽取方式。

micro-data

示例: http://microformats.org/ 以及各大网站

页面属性标记,通过在页面数据元素上增加属性标识,通过开放的标准格式,为数据提取提供便利,例如这是豆瓣的评论数据:

1
2
3
4
5
< p class="rating_self clearfix" typeof="v:Rating">
<span class="ll bigstar35"></span>
<strong class="ll rating_num" property="v:average">6.7</strong>
<span property="v:best" content="10.0"></span>
</p>

typeof="v:Rating" 表明这里是 rating 数据,v:best 表明 rating 的最大值。通过开放的 data format 标准,只按照标准抽取,就能得到包含的结构化数据。但是,需要站长的支持,在页面中加入标记才可以。

从广义上讲,主图识别,页面发布时间这样的属性,其实也可以是通过对页面内容进行分析获得的。这与 micro-data 一样,通过元素足够强的特征,对元素的含义进行理解分析。

模板生成与提取

image

页面模板(wrapper)抽取是基于这样一个假设:结构化页面都是 通过模板 将数据库中的数据 映射成页面的。通过页面分析,得到页面模板,通过模板提取出实际的结构化数据。

例如,我使用过的方法,将多个相似页面放在一起比对,寻找等位节点(具有相同结构或表示相同数据类型的元素),将 DOM树 合并。通过比较不同页面上的同类节点,能够获知页面中哪部分是变化的,哪部分是不变的。变化的部分为数据,不变部分为模板。最后形成如上图所示的模板,页面变化部分被涂黑。这个方法类似于将多张纸叠在一起,透过光去看,就会发现变化的文字部分会比其他部分更黑。

当然了,这个方法也有缺陷,例如:页面一页面二 的标题部分,一个是蓝色,一个是绿色,虽然在人类视觉上它们相差不大,但从页面结构上绿色多了一层 <font>,作为算法很难理解,这样的样式表示他们是否有相同的含义,是否有区别。同理左侧推荐的蓝绿相间,即使作为人也很难理解它们有什么区别。

##两个核心问题

总结起来,以上四种解析模式都在尝试解决以下两个问题:

一个元素在说什么

当你打开一个页面,你怎么知道一个页面在传递什么信息?你怎么知道一个元素是文章的标题?怎么知道一个元素是作者?作为人类,我们可能会看到一个元素的位置是否在页面中间,元素的字体大小、颜色,元素前面是不是有一个 “作者:”,元素内容是否长得像一个人名/时间,上下文中这个元素都在讲什么,这篇文章是什么领域,等等。人类可能会有非常多的 经验知识 ,当看到一个页面的时候能够解读出页面上的信息。

在 “xpath / css选择器 / 正则表达式” 的解析模式中,这个工作正是人肉去完成的,人去解读这个页面,找到信息所在元素。而在 “data highlighter” 的解析模式中,也需要人在多个页面中进行标注,告诉机器每个属性所在。

但是作为计算机,是否能做到这一点?micro-data 通过开放的格式约定,通过 property 这一个特殊的属性标记告诉计算机一个元素说的是什么。而模板挖掘通过:xpath,元素class,id属性,上下文等特征去挖掘元素的含义。

但是,页面样式结构,在人类在没有足够的知识情况下,也有可能会无法解读,例如我们的爷爷奶奶可能就看不懂网页上说的是什么。同时,正如语言是有二义性的一样,页面结构也会如此,这给计算机去理解,页面说的是什么,带来了巨大的困难。

这个元素和其他的元素有什么区别

因为,大批量数据抽取是计算机的活,这需要 准确 地告诉计算机,你想要抽取的元素是哪一个。在 “xpath / css选择器 / 正则表达式” 的解析模式中,xpath、css选择器、正则表达式正是对这一信息的描述。选取一个正确的表达式,即涵盖不同页面,又和其他属性有所区分,是一件需要经验和技巧的工作。而 “data highlighter” 将这个工作交给了计算机。“模板生成和套用” 过程中也由计算机分析出了规则。

而对于 “micro-data” 来说,这个问题有些特殊。通过开放的标准格式,程序已经能够了解每个元素在说什么了,那么定位就不再有意义。但是反过来,这又何尝不是一种定位。

结构化解析

结构化解析实质是计算机对一个页面的理解,无论这种理解是人去创建规则、做出某种约定 还是 机器学习。上面列举的四种解析方式,“xpath / css选择器 / 正则表达式” 和 “data highlighter” 回答了这个元素和其他的有什么区别。 “micro-data” 利用了一个元素在说什么。而 “模板生成与提取” 同时涉及元素说什么,它在哪。

那么作为结构化解析的究级形态是怎样?我们可以假想一个人,他打开一个页面就能知道上面说的是什么,有什么样的信息,这是人类对于:通过网页获取知识的一种能力,一种方式。计算机也是一样,结构化抽取 就是 计算机从网页中获取知识的过程。“这个元素和其他的元素有什么区别” 终究只是在无法达到:计算机理解 一个页面在说什么 的辅助手段。理解 “一个元素在说什么” 乃至 “一个页面在说什么” 我认为是才是其究级形态,而结构化数据也不过是计算机,对于浩瀚互联网信息理解的一种表达罢了。