无关标签的一般长文本网页正文内容抽取
一般的网页内容抽取需要针对特定的网站进行特定的检查定位正文标签,指定抽取规则。但是如果需要抽取100个不同内容结构的网站正文,需要的就是100个不同的规则。
有没有一种通用的内容抽取呢。可以只基于网页正文内容的变化而变化的规则f(x).
本文实现的是针对于一般的长文本正文类网站(博客、新闻、小说类)实现的通用正文内容抽取。像那种需要抽取的正文内容C长度与网页内容W长度比例C/W<0.5的可能会出现不适用的情况。(比如正文是一句话几个字,整个页面内容的文字长度超过了正文的2倍,那最好使用DOM标签规则抽取)
以下的“网页”均指长文本类型的网页
为什么抽取正文
一般的网页正文都是属于段落类型的文本,所属标签不一,其他的无用信息(如网页版权、站点通知、导航内容等)也占据了一定的页面内容,如果单纯的把网页内容文字全部抽取出来,
这很简单,但是会夹杂很多的无用内容,干扰太大,所以针对正文抽取得到页面的真正有用信息是主要目的。可以利用正文内容进行网页相似度的计算。
怎么抽取正文
抽取正文要找到正文的分布特征,将爬取到的网页去除所有标签,得到每一行的内容后,可以根据(行号,字符数)制作图表查看两者的关联:
下图是腾讯新闻一则新闻页面的行号-行字数关系图表:
下图是CSDN的两则博文正文行号-行字数关系图表:
《中文编码相关,python处理gbk编码的xml文件方法》:
《python抓取gb2312gbk编码网页乱码问题》:
下图是segmentfault的一篇博文正文行号-行字数关系图表:
《解决 ScriptError的另类思路》:
可以看到,正文的内容一般是连续行的块,因此我们可以设置阈值来过滤一些非正文的干扰行,但是针对某些连续行并不是有效正文的情况,就需要看这个连续行组成的块的总字符数。
如果字数少于一个阈值,就不属于正文,也就是正文的字符密度,由此可见,正文可以基于连续行字符密度来进行提取。
算法实现
假设我们已经爬取了网页内容WebContent,并且将W的所有标签去除得到了纯文本保留行格式的文字内容LinesContent.接下来:
#三个可控变量,自由调整使抽取达到理想效果
#连续行阈值:连续多少行则认为是一个正文内容块
threshold = 5
#正文内空行阈值:允许正文内容 段落或正文行 之间有多少空行
gap = 3
#正文字符密度阈值:每一行的字符数达到多少则认为属于正文内容
density = 45
#********初始化设置#********
#保留抽取结果字典,格式:{<连续块字符总数>:<块文字内容>,...}
results={}
#已经达到前后连续的次数
comobo_num =0
#当前连续块的总字符数
combo_len = 0
#当前连续空行数
combo_null=0
#当前连续块的文字内容
combo_text = ''
#当前行/前一行的字符数
pre_len = 0
for i in LinesContent:
#当前行非空
if i.strip():
pre_len = len(i)
comobo_num += 1
combo_null = 0
combo_len += pre_len
#叠加非空行内容到连续内容中
combo_text = combo_text+i+ os.linesep
#针对单行文本情况
if len(a)==1 and pre_len >= density*threshold:
results[pre_len]=combo_text
else:
combo_null +=1
#如果前一行非空
if pre_len:
#连续空行阈值判断
if combo_null > gap:
#连续块判断
if combo_len >= density*threshold \
and comobo_num >= threshold:
results[combo_len]=combo_text
else:
continue
#非正文连续块则全部参数复位
comobo_num = 0
combo_len = 0 if combo_null > gap else combo_len
pre_len = 0
combo_text = '' if combo_null > gap else combo_text
经过对多个长文本类型网站的抓取抽取,正文抽取成功率达到了90%以上。
Todo
- 针对有图片嵌入的正文抽取
- 连带正文标签的抽取
- 正文格式的保存
源码地址:GitHub
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。