设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

我为开源做贡献,网页正文提取——Html2Article

2014-1-7 14:38| 发布者: 红黑魂| 查看: 33139| 评论: 5|原作者: StanZhai|来自: 博客园

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

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

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

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

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

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

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

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

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

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

int preTextLen = 0;         // 记录上一次统计的字符数量(lines就是去除html标签后的文本,_limitCount是阈值,_depth是我们要分析的深度,sb用于记录正文)int startPos = -1;          // 记录文章正文的起始位置for (int i = 0; i < lines.Length - _depth; i++){    int len = 0;    for (int j = 0; j < _depth; j++)    {        len += lines[i + j].Length;    }    if (startPos == -1)     // 还没有找到文章起始位置,需要判断起始位置    {        if (preTextLen > _limitCount && len > 0)    // 如果上次查找的文本数量超过了限定字数,且当前行数字符数不为0,则认为是开始位置        {            // 查找文章起始位置, 如果向上查找,发现2行连续的空行则认为是头部            int emptyCount = 0;            for (int j = i - 1; j > 0; j--)            {                if (String.IsNullOrEmpty(lines[j]))                {                    emptyCount++;                }                else                {                    emptyCount = 0;                }                if (emptyCount == _headEmptyLines)                {                    startPos = j + _headEmptyLines;                    break;                }            }            // 如果没有定位到文章头,则以当前查找位置作为文章头            if (startPos == -1)            {                startPos = i;            }            // 填充发现的文章起始部分            for (int j = startPos; j <= i; j++)            {                sb.Append(lines[j]);            }        }    }    else    {        if (len <= _endLimitCharCount && preTextLen < _endLimitCharCount)    // 当前长度为0,且上一个长度也为0,则认为已经结束        {            if (!_appendMode)            {                break;            }            startPos = -1;        }        sb.Append(lines[i]);    }    preTextLen = len;}

核心的提取算法不足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”也能找到很快的找打它,算法实现已经将近半年了,一直比较懒,也没写过文章跟大家分享一下。

本文版权归翟士丹(Stan Zhai)博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部