为什么要做正文提取

一般做舆情分析,都会涉及到网页正文内容提取。对于分析而言,有价值的信息是正文部分,大多数情况下,为了便于分析,需要将网页中和正文不相干的部分给剔除。可以说正文提取的好坏,直接影响了分析结果的好坏。

对于特定的网站,我们可以分析其html结构,根据其结构来获取正文信息。先看一下下面这张图:

正文部分,不同的网站,正文所在的位置不同,并且Html的结构也不同,对于爬虫而言,抓取的页面是各种各样的,不可能针对所有的页面去写抓取规则来提取正文内容,因此需要一种通用的算法将正文提取出来。

现有的网页正文提取算法

  • 基于标签用途的正文提取算法(比如title或h1,h2标签一般用作标题,p一般表示正文段落,根据标签的含义去提取正文)
  • 基于标签密度判定(这个简单,说白了就是字符统计,正文部分html标签的密度比较低,确定一个阈值,按照标签密度提取正文部分)
  • 基于数据挖掘思想的网页正文抽取方法(这里会涉及到统计学和概率论的一些知识,在高深点就成了机器学习了,没有深入研究)
  • 基于视觉网页块分析技术的正文抽取(CV这种高端大气上档次的东西,岂是我等这么容易就能研究明白的。虽然实现上复杂,但就提取效果而言,这种方法提取的精度还是不错的)

前2中方法还是比较容易实现的,主要是处理简单,先前我把标签密度的提取算法实现了,但实际用起来错误率还是蛮高的;后2种方法在实现上就略复杂了,从算法效率上讲应该也高不了哪去。

我们需要的是一种简单易实现的,既能保证处理速度,提取的准确率也不错的算法。于是结合前两种算法,研究网页html页面结构,有了一种比较好的处理思路,权且叫做基于文本密度的正文提取算法吧。后来从网上找了一下类似的算法,发现也有使用类似的处理方法来处理正文提取的,不过还是有些不同。接下来跟大家分享一下这个算法的一些处理思想。

网页分析

我任意取了百度,搜狐,网易的一篇新闻类网页,拿来作分析。

先看一篇百度的文章

任正非为什么主动与我合影,http://liyinghuan.baijia.baidu.com/article/2011

首先请求这个页面,然后过滤到所有的html标签,只保留文本信息,我们可以看到正文信息集中在一下位置:

使用Excel分析行数与每行的字符的关系可以发现:

很明显,正文内容集中在65-100行之间的位置上,而这个区间的字符数也是比较密集的。

再来一篇网易的文章

张小龙神话已破灭 马化腾该接管微信了,http://tech.163.com/13/1230/10/9HB88VE600094NRG.html

还是先看下过滤html标签后的正文部分:

再来一个Excel的分析结果:

正文部分集中在279-282行之间,从图上看,也正是这么几行的文本密度特别高。

最后分析一篇搜狐的新闻

李克强天津调研考察的几个瞬间,http://news.sohu.com/20131229/n392604462.shtml

还是先看下过后标签后的正文:

再看下Excel的分析结果:

而搜狐的这篇文章正文部分主要集中在200-255行之间。其余的文本全部是杂乱的标签文本。

抱歉,漏了很重要的一点说明:为什么分析的时候要把html标签过滤掉呢?过滤html标签是为了降低干扰,因为我们关注的是正文内容,如果带着这样的标签<span style="color: #0000ff;">var</span> chart = <span style="color: #0000ff;">new</span><span style="color: #000000;">去分析,可想而知,对我们的正文分析会有多大的干扰了,也正因如此需要将html标签掉,只对文本做分析,降低干扰。

基于网页分析构思出的正文提取算法

回顾以上的网页分析,如果按照文本密度来找提取正文,那么就是写这么一个算法,能够从过滤html标签后的文本中找到正文文本的起止行号,行号之间的文本就是网页正文部分。

还是从上面三个网页的分析结果看,他们都有这么一个特性:正文部分的文本密度要高出非正文部分很多。我们按照这个特性就可以很容易将算法实现,那就是基于阈(读音:yu)值去分析正文所在的位置。

那么接下来就需要解决一些问题:

  • 如何确定阈值?
  • 如何分析,一行行的分析?还是?

阈值的确定可以通过统计分析得出一个比较好的值,我在实际处理过程中,发现这个值取180是比较合适的,也就是分析文本的时候,如果所分析的文本超过了180,那么就可以认为到达了正文部分。

再有就是如何分析的问题,这个其实比较容易确定,一行行的分析效果肯定不好,如果在按行分析的过程中往下在分析几行作为一次分析效果比较好。也就是一次性分析上5行左右,将字符累加起来,看看有没有达到设定的阈值,如果达到了,那么认为已经进入正文部分了。

嗯,主要的处理逻辑就是这样,怎么样,不复杂吧。

我把实现的核心算法也贴出来吧:

  1. int preTextLen = ; // 记录上一次统计的字符数量(lines就是去除html标签后的文本,_limitCount是阈值,_depth是我们要分析的深度,sb用于记录正文)
  2. int startPos = -; // 记录文章正文的起始位置
  3. for (int i = ; i < lines.Length - _depth; i++)
  4. {
  5. int len = ;
  6. for (int j = ; j < _depth; j++)
  7. {
  8. len += lines[i + j].Length;
  9. }
  10.  
  11. if (startPos == -) // 还没有找到文章起始位置,需要判断起始位置
  12. {
  13. if (preTextLen > _limitCount && len > ) // 如果上次查找的文本数量超过了限定字数,且当前行数字符数不为0,则认为是开始位置
  14. {
  15. // 查找文章起始位置, 如果向上查找,发现2行连续的空行则认为是头部
  16. int emptyCount = ;
  17. for (int j = i - ; j > ; j--)
  18. {
  19. if (String.IsNullOrEmpty(lines[j]))
  20. {
  21. emptyCount++;
  22. }
  23. else
  24. {
  25. emptyCount = ;
  26. }
  27. if (emptyCount == _headEmptyLines)
  28. {
  29. startPos = j + _headEmptyLines;
  30. break;
  31. }
  32. }
  33. // 如果没有定位到文章头,则以当前查找位置作为文章头
  34. if (startPos == -)
  35. {
  36. startPos = i;
  37. }
  38. // 填充发现的文章起始部分
  39. for (int j = startPos; j <= i; j++)
  40. {
  41. sb.Append(lines[j]);
  42. }
  43. }
  44. }
  45. else
  46. {
  47. if (len <= _endLimitCharCount && preTextLen < _endLimitCharCount) // 当前长度为0,且上一个长度也为0,则认为已经结束
  48. {
  49. if (!_appendMode)
  50. {
  51. break;
  52. }
  53. startPos = -;
  54. }
  55. sb.Append(lines[i]);
  56. }
  57. preTextLen = len;
  58. }

核心的提取算法不足60行,经过验证提取的效果还是非常不错的,至少做到了正文提取正确率90%上,效率上做到了平均提取时间30ms左右。

还需解决的一些问题

html标签剔除:这个简单,直接使用正则表达式替换(Regex.Replace(html, "(?is)<.*?>", "")),将所有的html标签剔除即可

html压缩型网页的处理: 压缩后的html代码一般只有一行,对这类的html处理也比较简单(不需要复杂的代码格式化),直接在标签末尾强制添加换行符即可。

正文标题:大多数规范的网址会用h1标签作文正文标题,处理时如果有h1那么从h1标签中提取标题,没有的话,直接从title标签中那吧。

文章发布时间:并不是所有的文章都有发布时间(不过貌似大多数都有哈),直接使用正则从去除标签后的正文中提取时间吧。

保留带标签的正文:我们的算法是和标签无关的,因为算法处理时首先要过滤html标签,去除干扰,那么如果想要带标签的正文怎么办(比如要保留正文中的图片)?这时只能保留2个数组了,一个数组存放过滤标签的文本,便于分析,另一个数组则保留html标签,便于提取原始信息。

Html2Article网页正文提取算法

Html2Article就是我基于以上思想实现的网页正文提取算法。有以下特点:

  • 标签无关,提取正文不依赖标签。
  • 支持从压缩的html文档中提取正文内容。
  • 支持带标签输出原始正文。
  • 核心算法简洁高效,平均提取时间在30ms左右。

算法已开源(也算是为开源做点贡献了吧):

http://blog.zhaishidan.cn/Html2Article/

https://github.com/stanzhai/Html2Article

http://www.oschina.net/p/html2article

使用方法请参考文档介绍说明。

算法是用C#实现的,玩.NET的同学有福了,可以直接使用nuget将html2article添加到你的项目中哦。

另外发现直接从百度搜索“html2article”也能找到很快的找打它,算法实现已经将近半年了,一直比较懒,也没写过文章跟大家分享一下。

我为开源做贡献,网页正文提取——Html2Article的更多相关文章

  1. 利用Readability解决网页正文提取问题

    分享: 利用Readability解决网页正文提取问题   做数据抓取和分析的各位亲们, 有没有遇到下面的难题呢? - 如何从各式各样的网页中提取正文!? 虽然可以用SS为各种网站写脚本做解析, 但是 ...

  2. 分享: 利用Readability解决网页正文提取问题

    原文:http://www.cnblogs.com/iamzyf/p/3529740.html 做数据抓取和分析的各位亲们, 有没有遇到下面的难题呢? - 如何从各式各样的网页中提取正文!? 虽然可以 ...

  3. 网页正文提取,降噪的实现(readability/Document)

    安装: pip install readability-lxml 使用: # encoding:utf-8import html2textimport requestsimport refrom re ...

  4. Python网页正文转换语音文件的操作方法

    天气真的是越来越冷啦,有时候我们想翻看网页新闻,但是又冷的不想把手拿出来,移动鼠标翻看.这时候,是不是特别想电脑像讲故事一样,给我们念出来呢?人生苦短,我有python啊,试试用 Python 来朗读 ...

  5. 从 SDWebImage 谈如何为开源软件做贡献

    来源:伯乐在线 - 酷酷的哀殿 链接:http://ios.jobbole.com/89483/ 点击 → 申请加入伯乐在线专栏作者 从 SDWebImage 谈如何为开源软件做贡献 相识 – 知我者 ...

  6. 使用GitHub进行协同项目开发和开源项目贡献

    本教程致力于摆脱git命令行快速的学习使用GitHub. 此次是GitHub课程的第三次课程,也是最后一次课程.推荐进行按照次序查看本次教程.上篇文章:程序员,一起玩转GitHub版本控制,超简单入门 ...

  7. 算法工程师想进一步提高竞争力?向TensorFlow开源社区贡献你的代码吧

    算法工程师为什么也要向社区贡献代码? [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] “做算法的人要熟悉算法框架源码吗?算法工程师难 ...

  8. 按示例学python:使用python抓取网页正文

    平时打开一个网页,除了文章的正文内容,通常会有一大堆的导航,广告和其他方面的信息.本博客的目的,在于说明如何从一个网页中提取出文章的正文内容,而过渡掉其他无关的的信息. 这里先看看 demo : ht ...

  9. 如何往Spark社区做贡献,贡献代码

    随着社区正在努力准备Apache Spark的下一版本3.0,您可能会问自己“我如何参与其中?”.现在的Spark代码已经很庞大,因此很难知道如何开始自己做出贡献.Spark PMC & Co ...

随机推荐

  1. linux io stack

  2. 实现Unicode和汉字的相互转换

    <title>汉字和Unicode编码互转</title><script Language=Javascript>var classObj= { ToUnicode ...

  3. WPF 动画效果

    线性插值动画.关键帧动画.路径动画 1. (Visibility)闪烁三下,停下两秒,循环: XAML: <Grid> <Grid.ColumnDefinitions> < ...

  4. ios结构体语法

  5. List转换成XML

    protected void Button1_Click(object sender, EventArgs e) { var customerlist = CustomerHelper.GetList ...

  6. Excel Note

    公式的引用分为相对引用.绝对引用和混合引用.如果要使公式中的引用随着公式的下拉改变就用相对引用.如=sum(A2:D20),这个公式下拉时引用的单元格就会随着变化.如果要使公式中的引用下拉时不会改变就 ...

  7. iptables参数详解

    iptables参数详解 搬运工:尹正杰 注:此片文章来源于linux社区. Iptalbes 是用来设置.维护和检查Linux内核的IP包过滤规则的. 可以定义不同的表,每个表都包含几个内部的链,也 ...

  8. [原创]java WEB学习笔记109:Spring学习---spring中事物管理

    博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好 ...

  9. 在virtualbox中安装CentOS-7

    当初才接触linux的时候,因为条件限制,只能在虚拟机中安装linux系统使用,由于是小白,爬了好多坑.于是决定写一篇关于在虚拟机中安装linux系统的博客.一是为了巩固自己的知识,二是希望能够对新手 ...

  10. Ubuntu/linux 有关权限修改的命令

    chmod更改文件权限命令 最常用的基础命令chmod chmod 777  目录名(路径名) 777 三位数字分别代表 user.group.others 的权限,可读(r).可写(w).可执行(x ...