精确提取新闻内容

以前在《数学之美》的“余弦定理和新闻的分类”一文中看到,2002年夏天,Google推出了自己的新闻服务,而这些内容来源于对其它新闻网站内容的抓取、整理和分类,而构建这个新闻网站的关键技术是新闻的自动分类。我相信了作者,认真学习了书中介绍的新闻自动分类技术:利用余弦定理计算新闻相似度的层次聚类和利用奇异值分解的聚类。之后,我就觉得自己掌握了自动构建新闻网站的绝技。然而,直到最近,我才如梦初醒,发现自动构建新闻网站并不如之前想的那么简单。而破碎我的梦的并不是新闻聚类(我都还没走到这一步),而是精确提取新闻内容。
以前认为简单,是因为我把新闻内容整理想得太简单了——仅仅是获得网页中的纯文本。这或许对一个粗陋的新闻类垂直搜索引擎来说够了,然后,新闻读者和搜索引擎需要的输入不一样,我们并不能直接把包含新闻的网页中的纯文本直接扔给读者就了事,而是需要提供给读者内容完整、不含杂质(广告、别人网站的网页框架等)的新闻。精确提取新闻内容本是不易之事,然而还需对这个不易之事加一个前提条件:海量新闻。针对这个问题,我先介绍我所知的几个有启发意义的正文提取方法以及它们的问题,然后给出自己的解法。

《基于行块分布函数的通用网页正文抽取》一文中提出的网页正文抽取方法可能是网络上流传最广的方法了。它的思想是,一个主题类网页(我们这里是新闻)详情页只有一个数据区域,只要提取出这个数据区域就行了;找到这个数据区域的方法是,对网页内容分块,一块是指从某一行开始至某一行结束的区域,举个例子,第n块由第n行、n+1行和n+2行组成,第n+1块由第n+1行、n+2行和n+3行组成,然后提取出每一块中的纯文本,其中纯文本最多的那一块一定包含在正文之中;找到了之中的某一块,就可以利用这部分内容来找到正文边界了,文中指出,主题类网页的正文部分纯文本很多,而其它部分则较少,可以从之前定位到那一个块的位置开始往前往后找,找到的纯文本数量骤降点,就是边界了;最终利用边界信息提取出正文。这个方法能够准确的提取出大部分新闻的正文。我们以新闻:
http://society.people.com.cn/n1/2015/1226/c1008-27978755.html
为例,根据文章作者提供的代码,它能够提取出新闻正文,但在正文最后包含一些杂质信息。而且,该方法也真的只能提取出正文,难以提取出与正文相关的那些非常重要的信息,也就是新闻的标题、来源、时间和标题与正文之间的图片,对于例子网页,丢失的是这部分信息:

多了信息不可怕,我们可以对得到的内容进一步提纯,可怕的是,它可能会丢失我们想要的信息,丢了就找不回来了。

第二方法就是大名鼎鼎的Readability算法。这个算法是并不是专门针对主题类网页而提出的,它是一个通用的算法,能够针对输入的任何网页返回一个比较干净的网页。它的主要思想是,通过给定网页构建一棵DOM树,对其中body节点子树中的每一个后代节点打分,获得得分满足要求的节点,这些节点包含读者想读的内容,然后把这些节点整理为一个网页返回。用该算法的Java实现处理上面的示例新闻,结果跟上一种方法差不多。不过,通过DOM树,可以容易用另外的方式获得新闻的时间和来源。新闻时间可以通过在标题和正文之间的内容上通过正则表达式匹配出来;来源则可以在标题和正文之间的内容上通过“来源”关键字找出,并把找到的来源存储起来,用于在这部分内容中没有“来源”关键字的时候去匹配来源;最终解决问题。如果它对任何新闻类网页都只是不能提取新闻的来源和时间的话,那它就已经能满足精确提取新闻内容的要求了,可是,它还有其它问题,比如,大部分情况下会丢失新闻标题和正文之间的图片等信息,有时在正文之后还会存在另外一些不需要的信息(二维码图片,版权信息等)。同样,核心问题在于信息丢失。

第三种方法是RoadRunner。这个算法试图从一组由相同模板生成的网页中发现模板,然后用这个模版去解析由这个模板生成的其它网页。这个算法的目标是让人心动的,但是我尝试这个算法的一个开源实现,却总是不能得到预期的结果。暂时还没有深入学习该算法的具体实现,对其细节了解不深,故这里就不多讲了,文章后面会给出我尝试的开源实现,大家有兴趣可以试试。

最后,我给出我的解法。这个解法是基于《基于行块分布函数的通用网页正文抽取》和Readability算法的。该解法基于这样一些事实:
(1)新闻详情页只有一个数据区域;
(2)组成数据区域的节点是兄弟节点,它们有共同的父节点;
(3)如果利用Readability算法中给节点打分的方式给文档树中的body节点的后代节点打分,那么得分最高的节点必定是组成数据区域的节点的某个祖先节点——正文节点;
(4)这个正文节点的后代节点中可能包含标题节点,也可能不包含标题节点(有用的废话)。
基于(1)(2)(3),我们可以很容易获得正文节点,我们可以利用新闻标题和网页标题之间的一些关系(比如新闻标题是网页标题的子串)来获得标题节点。我们可以求得新闻标题节点和正文节点最近公共父节点——新闻节点,这个节点内包含我们想要的新闻内容,并且已经去除了网页中的大部分杂质。接下来,我们要做的就是去除新闻节点中没有被剔除的杂质,比如从新闻节点到正文节点的路径右边的所有节点都该删除。基于(4),我们需要分情况处理标题节点周围的信息。剔除信息的标准是,宁可放过,也不错杀,这保证了我们需要的信息永远都在。然后,经过层层清洗,最终得到干净的新闻。我已经实现了该解法,并且经过简单测试,发现效果不错。但是没有经过专业测试,而且实现也没有做到极致,最终是否能剔干净所有杂质并没有得到验证,这里写出来有两个目的,一是记录下来,帮助理清思路,二是分享给大家,望有经验的大神给些建议。

相关源码链接:
Readability
基于行块分布函数的通用网页正文抽取
RoadRunner
参考文献:
基于行块分布函数的通用网页正文抽取,作者:陈鑫。
《Web数据挖掘》第二版,作者:Bing Liu,译者:俞勇。

你可能感兴趣的:(web数据挖掘,正文抽取)