V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
irainy
V2EX  ›  分享创造

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

  •  1
     
  •   irainy · 2015-09-03 00:03:40 +08:00 · 4816 次点击
    这是一个创建于 3148 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Original post

    问题:如何提取任意(尤其是新闻、资讯类)网页的正文内容,提取与文章内容相关的图片,源码可见:extractor.py

    抓取单个网站网页内容时通常采用正则匹配的方式,但不同网站之间结构千奇百怪,很难用统一的正则表达式进行匹配。《基于行块分布函数的通用网页正文抽取算法》的作者总结了一般从网页中提取文章正文的方法,提出基于行块分布的正文抽取算法,并给出了 PHP 、 Java 等实现。这一算法的主要原理基于两点:

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

    算法步骤如下:

    • 去除所有 tag ,包括样式、 Js 脚本内容等,但保留原有的换行符\n
    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]$ 行文本之和并给出行块长度基于行号的分布函数:
    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 的范围:
    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>标签的内容:
    reIMG  = re.compile (r'<img[\s\S]*?src=[\'|"]([\s\S]*?)[\'|"][\s\S]*?>')
    def processImages (body ):
      return reIMG.sub (r'{{\1}}', body )
    

    总结

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

    参考

    5 条回复    2015-12-20 00:31:12 +08:00
    Tink
        1
    Tink  
       2015-09-03 04:48:52 +08:00 via iPhone
    有想法
    gamexg
        2
    gamexg  
       2015-09-03 13:37:24 +08:00 via Android
    感觉多网页对比更清楚吧?
    同一个网站 url 类似的布局应该一致,比较不同的部分就可以找到标题内容广告等块。
    jeremaihloo
        3
    jeremaihloo  
       2015-09-03 22:37:35 +08:00 via Android   ❤️ 1
    irainy
        4
    irainy  
    OP
       2015-09-03 22:57:06 +08:00
    piapia
        5
    piapia  
       2015-12-20 00:31:12 +08:00
    觉得印象笔记的 chrome 插件提取的很准确
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5483 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:56 · PVG 14:56 · LAX 23:56 · JFK 02:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.