从HTML文件中抽取正文的简单方案 试验结果

HTML文件中抽取正文的简单方案 试验结果

 

 

 标签:人工智能、AI、BP网络、html净化、分类、正文抽取

 

 

一、简介

本文是根据alexjc一文进行实验的结果。原文见:

http://ai-depot.com/articles/the-easy-way-to-extract-useful-text-from-arbitrary-html/

——alexjc原文

 

http://blog.csdn.net/lanphaday/archive/2007/08/13/1741185.aspx

——恋花蝶翻译的中英对照版本

 

该文章主要内容是讲述如何利用正文相对于其他文本,正文文本与生成该正文所需的html字节码的比值较大的规律,利用神经网络识别出正文过滤过滤广告的效果。主要设计如下:

 

1.       解析HTML代码并记下处理的字节数。

2.       以行或段的形式保存解析输出的文本。

3.       统计每一行文本相应的HTML代码的字节数

4.       通过计算文本相对于字节数的比率来获取文本密度

5.       最后用神经网络来决定这一行是不是正文的一部分。

 

 

二、设计方案

本实验相对原本alexjc设计方案有几点修改:

 

1.       RPROP(弹性BP网络)代替原文的感知器;

2.       由于原文并没有把文本长度、html字节长度做归一化,所以不采用原始文本长度、html字节长度作为特征值。相对的,对归一化后的文本长度、html字节长度,以及前向后向N行等各种组合进行试验。

3.       试验文本为任意在网上选取的10个网页,见附件。

4.       原文并没有提及,如何定义一行文本是否正文,所以这里定义了几个正文类型:

a)         内容型正文,特征是有长的连续文字段,定义这些文字段为正文;

b)         论坛型,有短的不连续的文字段,定义这些文字段为正文;

c)         论坛帖子列表型(部分试验将会对这类型进行训练查看效果,对于论坛帖子列表是否属于正文这里不做讨论……),帖子标题为正文;

d)         首页型,定义为没有正文(厄,谁能说出,新浪首页哪些是正文?)

 

实验环境:

1.       语言:JAVAJRE1.5

2.       操作系统:windows xp

 

三、实验过程:

1.       设计实现一个三层RPROP网络(令人惊讶的是,居然在这个领域没有人写一个开源的组件,apache等的开源巨头们都对neural network不感兴趣么?)。

 

/*

*初始化RPROP对象

*

*本函数用于创建训练前的RPROP对象

*参数:

*        int in_num     输入层个数;

*   int hidden_unit_num  隐含层节点个数

*   int out_num   输出层个数

*

*/

    public RPROP(int in_num, int hidden_unit_num, int out_num)

 

/*

*初始化RPROP对象

*

*本函数用于创建训练后的RPROP对象

*参数:

*        int in_num     输入层个数;

*   int hidden_unit_num  隐含层节点个数

*   int out_num   输出层个数

*   double[][] w1 隐含层权重

*   double[][] w2 输出层权重

*   double[] b1   隐含层偏离值

*   double[] b2   输出层偏离值

*/

public RPROP(int in_num, int hidden_unit_num, int out_num, double[][] w1, double[][] w2, double[] b1, double[] b2)

 

/*

*计算输出结果

*

*参数:

*   double[] p 输入参数

*返回值:

*   double[] 输出结果

*/

public double[] output(double[] p)

 

/*

*训练

*

*参数:

*   double[][] p 

*          训练样本集

*   double[][][] t   

*          期望结果集, t[i][j][0] 期望结果, t[i][j][1]误差放大系数

*   double goal  

*          目标误差,注意,本网络用的是“方差”作为误差判断条件

*   int epochs

*          训练最大次数

*/

public void train(double[][] p, double[][][] t, double goal,int epochs)

对于这个实现,有兴趣的朋友在本文最后下载附件。

 

2.       选取特征值

在实验中,笔者尝试了各种特征值组合:

1)       文本密度,文本长度,html字节码长度,前后各一行的同样数值;(原文设定)

2)       文本密度,文本长度倒数(归一化),前后各两行的同样数值;

3)       文本所在的html的链接密度(全文文本长度/总链接数,用于加强判断文本类型),文本密度,文本长度/5000(归一化,大于1的当1处理,下文简称为文本长度2),前后两行相同的数值;

4)       文本所在的html的链接密度,文本密度,文本长度2,前后两行相同的数值;

5)       文本所在的html的链接密度,文本密度,文本长度2,前后一行相同的数值;

6)       文本所在的html的链接密度,文本密度,文本长度2,前一行是否正文;

 

并规定,网络输出结果0为非正文,1为正文。

 

在训练过程中,发现训练过的网络命中率大部分落在0值部分,这是由于论坛这种短文段类型的网页会导致0值过多,训练时对0值过拟合。为了避免这一点,对某一篇网页的某一行的误差乘以该网页的0值与1值数量的比值。

 

3.       训练集获取

见附件。这是在笔者常浏览的网页中任意抽取的10个网页。对于期望输出的定义见上文。

 

四、实验结果

1.         15的实验,任意抽取部分样本集作为训练集,对于训练集拟合的很好,但对于测试集的表现却非常糟糕(请原谅笔者并没有记录实验数据);

 

这部分结果表明,以文本密度作为判断是否正文的特征值是有问题的。观察样本集的数据可以发现,即使是内容型的大段文字,也有可能文本密度很低——为了让网页变得更漂亮美观,现在有很多网站都对文字内容加了大段大段修饰用html代码……

鉴于这一点,笔者最终放弃文本密度作为特征值。而考虑到广告都是带链接的文本,相对的正文连接数则比较少,所以笔者认为,用文本长度/链接数 作为特征值或许会是一个更好的选择。

 

2.         6的实验,表现意外的非常的好(好到差点让笔者以为终于找到完美的解决方案……)

确实,即使是在测试集部分的表现也惊人好,但实际上有一个问题:每一行的计算受上一行计算的结果影响。测试集是事先定义每一行的上一行的结果,但在实际使用时,上一行的结果是实时计算出来的,所以就会出现,在某一行出错,导致后面的结果全部出错的情况……

 

至此,假如仍然坚持神经网络的解决方案,或许,采用:

文本长度,文本长度链接数,上一行的结果 做特征值, 采用三个弱分类器的ada-boost组合分类或许会是一个好的选择。

除此之外,实际上对正文的定义对结果也是有很大的影响。实际上,假如能根据数据化的东西定义某一个类别,那么对于该类别的划分,或许其实已经是可预知的,不如直接设计阈值处理。

 

笔者的实验则到此为止,并放弃了神经网络这个解决方案——直接采用这些特征值进行阈值判断,并对一些特殊部分设定过滤规则,这似乎比神经网络的表现来的简单、有效……

 

如果有哪位朋友感兴趣,并用ada-boost进行实验,笔者将非常期待这位朋友来交流下心得:)

 

附件:
neralNetwork.rar  源代码
res.rar 训练集

厄,俺不知道csdn的附件怎么上传,就丢个链接吧,俺的javaeye的博客同一个位置:

http://hzxdark.javaeye.com/admin/blogs/119239

 

关于html文本抽取部分,这里用的是HtmlParser,这里就不贴出来了,有兴趣的朋友可以去:
http://htmlparser.sourceforge.net/
看看。

你可能感兴趣的:(技术人生)