网页正文及内容图片提取算法

2015-09-03 00:03:40 +08:00
 irainy
→ [Original post]( http://blog.rainy.im/2015/09/02/web-content-and-main-image-extractor/) ←

**问题:**如何提取任意(尤其是新闻、资讯类)网页的正文内容,提取与文章内容相关的图片,源码可见:[extractor.py]( https://github.com/rainyear/cix-extractor-py/blob/master/extractor.py )。

抓取单个网站网页内容时通常采用正则匹配的方式,但不同网站之间结构千奇百怪,很难用统一的正则表达式进行匹配。[《基于行块分布函数的通用网页正文抽取算法》]( http://cx-extractor.googlecode.com/files/%E5%9F%BA%E4%BA%8E%E8%A1%8C%E5%9D%97%E5%88%86%E5%B8%83%E5%87%BD%E6%95%B0%E7%9A%84%E9%80%9A%E7%94%A8%E7%BD%91%E9%A1%B5%E6%AD%A3%E6%96%87%E6%8A%BD%E5%8F%96%E7%AE%97%E6%B3%95.pdf )的作者总结了一般从网页中提取文章正文的方法,提出基于行块分布的正文抽取算法,并给出了 PHP 、 Java 等实现。这一算法的主要原理基于两点:

1. 正文区密度:在去除 HTML 中所有 tag 之后,正文区字符密度更高,较少出现多行空白;
2. 行块长度:非正文区域的内容一般单独标签(行块)中较短。

算法步骤如下:

- 去除所有 tag ,包括样式、 Js 脚本内容等,但保留原有的换行符`\n`:

``` python
reCOMM = r'<!--.*?-->'
reTRIM = r'<{0}.*?>([\s\S]*?)<\/{0}>'
reTAG = r'<[\s\S]*?>|[ \t\r\f\v]'

def processTags (body=""):
body = re.sub (reCOMM, "", body )
body = re.sub (reTRIM.format ("script"), "" ,re.sub (reTRIM.format ("style"), "", body ))
body = re.sub (reTAG, "", body )
return body
```

- 将网页内容按行分割,定义行块 $block_i$ 为第 $[i, i + blockSize]$ 行文本之和并给出行块长度基于行号的分布函数:

``` python
def processBlocks (body=""):
ctexts = body.split ("\n")
textLens = [len (text ) for text in ctexts]
cblocks = [0] * (len (ctexts ) - blockSize )

lines = len (ctexts )
for i in range (blockSize ):
cblocks = list (map (lambda x,y: x+y, textLens[i : lines-1-blockSize+i], cblocks ))
return cblocks
```

- 正文出现在最长的行块,截取两边至行块长度为 0 的范围:

``` python
def getContext (ctexts, cblocks ):
maxTextLen = max (cblocks )

start = end = cblocks.index (maxTextLen )
while start > 0 and cblocks[start] > min (textLens ):
start -= 1
while end < lines - blockSize and cblocks[end] > min (textLens ):
self.end += 1

return "".join (ctexts[start:end])
```

- 如果需要提取正文区域出现的图片,只需要在第一步去除 tag 时保留`<img>`标签的内容:

``` python
reIMG = re.compile (r'<img[\s\S]*?src=[\'|"]([\s\S]*?)[\'|"][\s\S]*?>')
def processImages (body ):
return reIMG.sub (r'{{\1}}', body )

```

### 总结

以上算法基本可以应对大部分(中文)网页正文的提取,针对有些网站正文图片多于文字的情况,可以采用保留`<img>` 标签中图片链接的方法,增加正文密度。目前少量测试发现的问题有: 1 )文章分页或动态加载的网页; 2 )评论长度过长喧宾夺主的网页。

### 参考

- [cx-extractor]( https://code.google.com/p/cx-extractor/)

- [cix-extractor-py]( https://github.com/rainyear/cix-extractor-py )
4828 次点击
所在节点    分享创造
5 条回复
Tink
2015-09-03 04:48:52 +08:00
有想法
gamexg
2015-09-03 13:37:24 +08:00
感觉多网页对比更清楚吧?
同一个网站 url 类似的布局应该一致,比较不同的部分就可以找到标题内容广告等块。
jeremaihloo
2015-09-03 22:37:35 +08:00
irainy
2015-09-03 22:57:06 +08:00
piapia
2015-12-20 00:31:12 +08:00
觉得印象笔记的 chrome 插件提取的很准确

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/217978

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX