基于行块分布函数的网页正文抽取算法代码实现

来源:互联网 发布:swatch集团 知乎 编辑:程序博客网 时间:2024/06/18 12:01

     最近在在做一个与资讯相关的APP,资讯是通过爬取获得,但是获取只有简单的信息,正文没有获取。所以在显示的时候很麻烦,一个<a>标签链到到别人的网页,满屏的广告

,还有各种弹窗,虽然页面确实做得很漂亮,但是不得不放弃这种简单的方式了,所以接下来自己动手了。

    首先我们做的是基于HTML5的APP,所以基本上就是和网页打交道。但是接下来问题就来了,当用户点击某一条资讯时,该由谁来解析这个网页最后呈现给用户看,手机端还是服务器端?其实都有问题,最简单的肯定是通过我们的服务器来解析后然后在封装成html给用户呈现,但是这样必定会增加服务器的压力,而且还有被封的可能性。在手机端,要取得html只有两种可能,js或者jsp,但是前者是不能跨域访问的,后者其实也是在服务器端运行的。最终解决方法,手机端用一个原生态的界面来呈现,不经可以解析链接,而且效果应该也比网页好,但是这和我们初心的不一致,那就是除了主界面其他都是网页,目前暂定这种方式。那么接下来问题又来了,改用什么方式来获取正文呢?有很多种算法,提供一篇算法介绍的博客:点击打开链接

     我使用的是基于行块分布函数的网页正文抽取算法,因为这个算法比较简单,准确率不是很高,基本思想:

        1.首先将网页中的html标签全部去掉,再去掉空白行和空白部分,得到文本

        2.再将文本的行按照一定的数量分成一个一个的块(注意这个分的数量对提取的精度有影响,具体有多大的影响自己试试吧)

        3.最后对这些块进行分析,找出骤升和骤降的块,最后分析取出骤升和骤降块之间的内容。

     代码如下(注释已经很清楚了):

         

package com.spider.a;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import com.spider.util.DefaultHttpUtils;public class Ctext {/** * 行分块的大小(块大小=BLOCKS+1) */private static int BLOCKS = 0;/** * 判断为正文的文字骤变率 */private static float CHANGE_RATE = 0.7f;/** * 每行最小长度 */private static int MIN_LENGTH = 10;public static void main(String[] args) {String html = DefaultHttpUtils.downloadHtml("http://blog.csdn.net/csh624366188/article/details/8096989");html = deleteLabel(html);Map<Integer, String> map = splitBlock(html);System.out.println(judgeBlocks(map));}/** * 去除html标签 * @param html 请求获得的html文本 * @return 纯文本 */public static String deleteLabel(String html){String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式      String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式      String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式      String regEx_anno = "<!--[\\s\\S]*?-->"; //html注释    html = html.replaceAll(regEx_script, "");    html = html.replaceAll(regEx_style, "");html = html.replaceAll(regEx_html, "");html = html.replace(regEx_anno, "");html = html.replaceAll("((\r\n)|\n)[\\s\t ]*(\\1)+", "$1").replaceAll("^((\r\n)|\n)", "");//去除空白行html = html.replaceAll("+| +| +", ""); //去除空白return html.trim();}/** * 将纯文本按BLOCKS分块 * @param text 纯文本 * @return 分块后的map集合,键即为块号,值为块内容 */public static Map<Integer, String> splitBlock(String text){Map<Integer, String> groupMap = new HashMap<Integer, String>();ByteArrayInputStream bais = new ByteArrayInputStream(text.getBytes());BufferedReader br = new BufferedReader(new InputStreamReader(bais));String line = null,blocksLine = "";int theCount = 0,groupCount = 0,count=0;//1.记录每次添加的行数;2.记录块号;3.记录总行数try {while((line=br.readLine())!=null){if (line.length()>MIN_LENGTH) {System.out.println(line);if (theCount<=BLOCKS) {blocksLine +=line.trim(); theCount++;}else {groupMap.put(groupCount, blocksLine);groupCount++;blocksLine = line.trim();theCount = 1;}count++;}}if (theCount!=0) {//加上没凑齐的给给定块数的groupMap.put(groupCount+1, blocksLine);}System.out.println("一共"+groupMap.size()+"个行块,数据行数一共有"+count);} catch (IOException e) {e.printStackTrace();}return groupMap;}/** * 分析每块之间变化的情况 * @param map 块集合 * @return 正文 */public static String judgeBlocks(Map<Integer, String> map){Set<Entry<Integer, String>> sets = map.entrySet();List<Integer> contentBlock = new ArrayList<Integer>();int currentBlock = map.get(0).length(); //当前行的长度int lastBlock = 0; //上一行的长度for(Entry<Integer, String> set:sets){lastBlock = currentBlock;currentBlock = set.getValue().length();float between = (float)Math.abs(currentBlock - lastBlock)/Math.max(currentBlock, lastBlock);if (between>=CHANGE_RATE) {contentBlock.add(set.getKey());}}//下面是取多个峰值节点中两个节点之间内容长度最大的内容int matchNode = contentBlock.size();System.out.println("一共有"+matchNode+"峰值点");int lastContent = 0;//前一个两节点之间的内容长度String context = null;//结果if (matchNode>2) { for(int i=1;i<matchNode;i++){String result = "";for(int j=contentBlock.get(i-1);j<contentBlock.get(i);j++){result +=map.get(j);}if (result.length()>lastContent) {lastContent = result.length();context = result;}}}return context;}}

  

0 0
原创粉丝点击