基于行块分布函数的网页正文抽取算法代码实现
来源:互联网 发布: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;}}
- 基于行块分布函数的网页正文抽取算法代码实现
- 基于行块分布函数的通用网页正文抽取算法初步认识
- 基于行块分布函数的正文抽取
- 基于行块分布函数的通用网页正文抽取:线性时间、不建DOM树、与HTML标签无关
- 基于广告链接和行块分布的网页正文抽取
- cx-extractor:基于行块分布函数的通用网页正文抽取:线性时间、不建DOM树、与HTML标签无关
- 网页正文的抽取
- [原]基于统计的中文网页正文抽取的研究
- 基于标题和正文依存树的中文网页正文抽取方法
- php实现的网页正文提取算法
- 怎样抽取网页标记之间的正文
- 基于网页分析构思出的正文提取算法
- 基于文本密度的新闻正文抽取方法之Python实现
- 利用HtmlParse抽取网页正文内容
- 基于hadoop的网页元素抽取
- 网页正文抽取中的网页编码字符集自动识别最佳方案
- 网页正文抽取中的网页编码字符集自动识别最佳方案 .
- Java实现的基于模板的网页结构化信息精准抽取组件:HtmlExtractor
- 问题汇总(软件篇)
- Hadoop--05--运行WordCount
- 虚幻4 使用脚本编译自己的工程
- 2016夏季练习——数论
- 【NOIP2001提高组T3】统计单词个数-字符串上的动态规划
- 基于行块分布函数的网页正文抽取算法代码实现
- Android性能优化之:绘制优化
- mysql索引
- nyoj655 光棍节的yy
- POJ1061 青蛙的约会
- poj1144
- arm汇编align伪指令详解
- POJ3177题解
- Linux下几款C++程序中的内存泄露检查工具