September 27
我也谈谈网页正文抽取
最近在做网页正文抽取的东西,需要从典型的新闻页面中取出网页的正文,尽可能地滤掉广告,并且找到文章的标题。
我所处理的网页还没有变态到内容全部用java script提取的地步。也就是说,信息的内容全部是在html代码中的明文。
网络中的html页面数以亿万计,不同的网站,甚至同一网站不同板块的构成也不尽相同,并且很多网站的代码是由服务器后台动态生成,也有可能代码本身可能就有错误。即使摸清了某网站的代码规律,修正了可能有的错误,但是所写的抽取程序可能也只能是对这个网站的这个板块有效,要做到能够针对各类不同页面都有一个比较好的抽取结果是一个有点意思的挑战。
首先n多论文已经定义了网页中存在的噪声,也就是诸如页面导航、广告信息等会对抽取结果的准确性产生干扰的信息。那么尽可能消除这些噪声是第一件事。在噪声基本消除的情况下,找到正文块就是第二件事了。不过我更加喜欢先判定正文区域,在正文中剔出噪声的想法。
作为噪声,和正文的一个很大的不同就是,正文多是非标签的文字性内容比较多,也就是很长的连续文字。网页中最为常见的噪声就是存在于<a>块中的链接信息,广告导航基本上都是以这样的形式存在的。但是简单地剔除<a>块也是不行的,因为许多网站的正文中出现的热门词汇都会附带一个相关的链接。
首先我将html源代码交由jtidy进行一个预处理,处理成规范的xml代码。之所以处理成xml代码,是我希望能够将其建立成为一颗dom树来进行反复的扫瞄处理。
得到dom树对象document后,首先进行第一轮扫描,扫除script块,style块,没有文字内容的空块。如果某节点下出现了连续的<a>块,则说明这些<a>块全部都是广告,因为正文中基本不会出现连续不断的链接,需要扫除。另外,许多网站的正文是由连续的<p>块组成的,那么针对这样的块,第一轮扫瞄中需要将其合并为一个<p>块。在合并两个<p>时,由于少了一个<p>,需要补充一个<br>块来补充一个换行。
经过第一轮扫描,代码应该已经干净了一些,这时我们可以开始寻找正文。正文可能存在于tr,td,div,p等块中,进行第二次扫描,提取这些节点,然后计算其文字内容的长度。一般情况下,正文所在的块文字长度应该会远远超过噪音块,但是也有极特殊情况数量众多的零碎的广告文字长度也能超过言简意赅的正文,这时我的方案是借鉴很多游戏中对连击的奖励,文字连续越长,越后面的文字得分越高,可能一个100个字长的段落第100个字就顶10个零碎的4字广告的得分( (1 + 2 + 3 + 4) * 10 = 100 )。这样越连续的文字得分就越高,保证正文尽可能地出线。
这时挑选出的正文一般也就是到位了,但是问题是很可能在头尾残留了一些<a>块广告。我认为这些<a>块广告与正文中广告有很大的不同。这些<a>广告的马脚就是其父节点,它们的父节点要么也包含了正文所在区域,也就是和正文平级,要么本身就是正文所在区域的一个子节点,很难是正文节点本身的。那么对疑似正文节点进行一次扫描,剔除那些父节点文字内容过大(包含了广告以及正文,即和正文平级)的<a>块,也剔除那些父节点文字内容过小的<a>块。
经过这样的处理,得到的内容基本上就是我们需要的正文了。下面就是要提取标题。
在代表整个网页的document中扫描一次,寻找那些有font字体的,strong的,h1的,title的节点,提取他们的信息。然后将得到的文字内容分词,查验分出来的词有多少是被正文包含的,包含最多的一半就是标题。但是这里要注意,有时候找到的节点本身是正文节点的子节点,那么无论怎么分,分出来都是完全包含的,所以要剔除那些本身是正文一部分的疑似标题。这样做对大部分网页也是有效了,但是对仅有的标题就在正文节点里的那些页面,目前为止我还没有特别好的想法。
这些日子也研究了一些别人的论文,有很多思想都非常好,也有很多人想到用马尔科夫,人工神经来训练。也许以后我会考虑用用看吧。现在这样也还可以,呵呵。