GNE 是一个通用的新闻正文抽取器,自从开源以来,已经被很多人用来作为新闻正文通用爬虫的重要组件。
GNE 的 Github 地址:https://github.com/GeneralNewsExtractor/GeneralNewsExtractor 。算法来自于《基于文本及符号密度的网页正文提取方法》 ,这个算法是完全基于 HTML 里面的信息来寻找正文。因此,它有一些先天性缺陷:
如果正文只有三五句话,但评论是长篇大论,提取就会失败
如果正文里面 html 标签太多,也会导致正文找错位置
经常提取到版权信息
但如果让人来看网页,就不会搞错。因为正文的位置和评论的位置肯定不一样,版权信息一般在最下面……这些可视化信号,是通过 CSS 来确定的,单纯从 HTML 中是看不到的。
GNE 输入的HTML,原本就是使用模拟浏览器输出的 HTML,并不是真正的网页源代码。既然如此,在使用模拟浏览器的时候,为什么不直接把每个节点的坐标信息都记录下来呢?在使用模拟浏览器的时候,只需要执行一段 JavaScript 代码,就可以把每个节点是否可见,每个可见节点的长宽高、左上角、右下角的坐标记录下来。这样,GNE 在解析正文的时候,可以参考这些信息,直接移除不可见的节点,并移除尺寸显然不合理、位置显然不正确的节点。从而大大提高正文识别的准确率。
基于可视化信号的提取效果如何呢?我们用一篇新闻来作为例子:广西省发生了一起事件,位置在来宾市,画面曝光 。
首先在浏览器的开发者工具里面,直接复制经过js 渲染后的源代码:
当我们直接使用 GNE识别正文的时候,运行效果如下图所示:
可以看到,提取到的信息是版权信息。
现在,如果使用经过修改的 HTML 代码,就能成功提取到正文,如下图所示:
那么,这个经过修改的 HTML 有什么特别呢?我们来看看它长什么样:
在body
标签下面的所有节点,都有一个属性叫做 is_visiable
,它的值是字符串的 true
或者 false
。如果值为 true
, 那么,还有一个属性叫做 coordinate
。它的值是一个 JSON 字符串,包含了这个节点的尺寸,坐标等信息。
那么,这些特殊的 HTML 是怎么生成的呢?如果你只是想做一个临时测试,那么其实只需要在Chrome 的开发者工具的Console(控制台)
标签页执行这样一段 js 代码就可以了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 function insert_visiability_info ( ) { function get_body ( ) { var body = document .getElementsByTagName ('body' )[0 ] return body } function insert_info (element ) { is_visiable = element.offsetParent !== null element.setAttribute ('is_visiable' , is_visiable) if (is_visiable) { react = element.getBoundingClientRect () coordinate = JSON .stringify (react) element.setAttribute ('coordinate' , coordinate) } } function iter_node (node ) { children = node.children insert_info (node) if (children.length !== 0 ) { for (const element of children) { iter_node (element) } } } function sizes ( ) { let contentWidth = [...document .body .children ].reduce ( (a, el ) => Math .max (a, el.getBoundingClientRect ().right ), 0 ) - document .body .getBoundingClientRect ().x ; return { windowWidth : document .documentElement .clientWidth , windowHeight : document .documentElement .clientHeight , pageWidth : Math .min (document .body .scrollWidth , contentWidth), pageHeight : document .body .scrollHeight , screenWidth : window .screen .width , screenHeight : window .screen .height , pageX : document .body .getBoundingClientRect ().x , pageY : document .body .getBoundingClientRect ().y , screenX : -window .screenX , screenY : -window .screenY - (window .outerHeight -window .innerHeight ), } } function insert_page_info ( ) { page_info = sizes () node = document .createElement ('meta' ) node.setAttribute ('name' , 'page_visiability_info' ) node.setAttribute ('page_info' , JSON .stringify (page_info)) document .getElementsByTagName ('head' )[0 ].appendChild (node) } insert_page_info () body = get_body () iter_node (body) } insert_visiability_info ()
如下图所示:
执行完成以后,重新打开Elements(元素)
标签页,就可以看到我们需要的属性已经添加到了各个节点里面。
如果你想要使用 Puppeteer 或者 Selenium 来实现同样爬虫,想批量自动化执行 JavaScript,我给出一个 Demo,大家可以参考:GitHub - GeneralNewsExtractor/GneRender: Render web page to add necessary info on every dom element. .
只需要执行如下几个命令:
1 2 yarn install node render.js
就可以在当前文件夹下面生成一个test.html
,就这是经过修改的特殊 HTML 了。
最新版本的 GNE 已经提交到了 Pypi,大家现在可以直接试用 pip 安装: