zoukankan      html  css  js  c++  java
  • 网页正文抽取(包含提取图片)

    转自:http://bbs.it-home.org/thread-12676-1-1.html

    /**
     *@author Xin Chen
     *Created on 2009-11-11
     *Updated on 2010-08-09
     *Email:  xchen@ir.hit.edu.cn
     *Blog:   http://hi.baidu.com/爱心同盟_陈鑫
     *Modified By : Yang @ http://www.chainlt.com
     */
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import dbhelper.TextTool;
    
    /**
     * <p>
     * 在线性时间内抽取主题类(新闻、博客等)网页的正文。 采用了<b>基于行块分布函数</b>的方法,为保持通用性没有针对特定网站编写规则。
     * </p>
     * 
     * @author Chen Xin
     * @version 1.0, 2009-11-11
     */
    public class TextExtract {
        private static List<String> lines;
        private final static int blocksWidth;
        private static int threshold;
        private static String html;
        private static boolean flag;
        private static int start;
        private static int end;
        private static StringBuilder text;
        private static ArrayList<Integer> indexDistribution;
        private static List<String> old_lines;
        private static String oldhtml;
    
        static {
            lines = new ArrayList<String>();
            indexDistribution = new ArrayList<Integer>();
            text = new StringBuilder();
            blocksWidth = 3;
            flag = false;
    
            /* 当待抽取的网页正文中遇到成块的新闻标题未剔除时,只要增大此阈值即可。 */
            /* 阈值增大,准确率提升,召回率下降;值变小,噪声会大,但可以保证抽到只有一句话的正文 */
            threshold = 86;
        }
    
        public static void setthreshold(int value) {
            threshold = value;
        }
    
        /**
         * 抽取网页正文,不判断该网页是否是目录型。即已知传入的肯定是可以抽取正文的主题类网页。
         * 
         * @param _html
         *            网页HTML字符串
         * 
         * @return 网页正文string
         */
        public static String parse(String _html) {
            return parse(_html, false);
        }
    
        /**
         * 判断传入HTML,若是主题类网页,则抽取正文;否则输出<b>"unkown"</b>。
         * 
         * @param _html
         *            网页HTML字符串
         * @param _flag
         *            true进行主题类判断, 省略此参数则默认为false
         * @return 网页正文string
         */
        public static String parse(String _html, boolean _flag) {
            flag = _flag;
            html = _html;
            preProcess();
            // System.out.println(html);
            return getText();
        }
    
        private static void preProcess() {
            html = html.replaceAll("(?is)<!DOCTYPE.*?>", "");
            html = html.replaceAll("(?is)<!--.*?-->", "");// remove html comment
            html = html.replaceAll("(?is)<script.*?>.*?</script>", "");// remove
                                                                        // javascript
            html = html.replaceAll("(?is)<style.*?>.*?</style>", "");// remove css
            html = html.replaceAll("(?is)style=".*?"", "");// remove css
            html = html.replaceAll("&.{2,5};|&#.{2,5};", " ");// remove special char
            oldhtml = html;
            html = html.replaceAll("(?is)<.*?>", "");
            // <!--[if !IE]>|xGv00|9900d21eb16fa4350a3001b3974a9415<![endif]-->
        }
    
        private static String getText() {
            lines = Arrays.asList(html.split("
    "));
            old_lines = Arrays.asList(oldhtml.split("
    "));
            indexDistribution.clear();
            boolean haveimg_arr[] = new boolean[old_lines.size()];
            for (int i = 0; i < lines.size() - blocksWidth; i++) {
                int wordsNum = 0;
                for (int j = i; j < i + blocksWidth; j++) {
                    lines.set(j, lines.get(j).replaceAll("\s+", ""));
                    wordsNum += lines.get(j).length();
                }
                indexDistribution.add(wordsNum);
                // System.out.println(wordsNum);
                if (old_lines.get(i).toLowerCase().contains("<img")) {
                    haveimg_arr[i] = true;
                }
            }
            start = -1;
            end = -1;
            boolean boolstart = false, boolend = false;
            text.setLength(0);
            for (int i = 0; i < indexDistribution.size() - 1; i++) {
                if (indexDistribution.get(i) > threshold && !boolstart) {
                    if (indexDistribution.get(i + 1).intValue() != 0
                            || indexDistribution.get(i + 2).intValue() != 0
                            || indexDistribution.get(i + 3).intValue() != 0) {
                        boolstart = true;
                        start = i;
                        continue;
                    }
                }
                if (boolstart) {
                    if (haveimg_arr[i]) {
                        continue;
                    }
                    if (indexDistribution.get(i).intValue() == 0
                            || indexDistribution.get(i + 1).intValue() == 0) {
                        end = i;
                        boolend = true;
                    }
                }
                if (boolend) {
                    StringBuilder tmp = new StringBuilder();
                    // System.out.println(start+1 + "		" + end+1);
                    for (int ii = start; ii <= end; ii++) {
                        if (haveimg_arr[ii]) {
                            String img = getImg(old_lines.get(ii));
                            if (img == null)
                                continue;
                            tmp.append(img + "
    ");
                            continue;
                        }
                        if (lines.get(ii).length() < 5)
                            continue;
                        tmp.append("<p>" + lines.get(ii) + "</p>
    ");
                    }
                    String str = tmp.toString();
                    // System.out.println(str);
                    if (str.contains("Copyright") || str.contains("版权所有"))
                        continue;
                    text.append(str);
                    boolstart = boolend = false;
                }
            }
            return text.toString();
        }
    
        public static String getImg(String s) {
            String img = TextTool.getBetweenOne(s, "<img", "</img>");
            if (img == null) {
                img = TextTool.getBetweenOne(s, "<img", "/>");
            } else {
                img = "<img" + img + "</img>";
            }
            if (img != null) {
                img = "<img" + img + "/>";
            }
            return img;
        }
    }

    PS:

    Q:经常看见的正则前面的 (?i) (?s) (?m) (?is) (?im) 是什么意思?
    A: 称为内联匹配模式,通常用内联匹配模式代替使用枚举值RegexOptions指定的全局匹配模式,写起来更简洁。
      (?i) 表示所在位置右侧的表达式开启忽略大小写模式
      (?s) 表示所在位置右侧的表达式开启单行模式。
      更改句点字符 (.) 的含义,以使它与每个字符(而不是除   之外的所有字符)匹配。
      注意:(?s)通常在匹配有换行的文本时使用
      (?m) 表示所在位置右侧的表示式开启指定多行模式。
      更改 ^ 和 $ 的含义,以使它们分别与任何行的开头和结尾匹配,
      而不只是与整个字符串的开头和结尾匹配。
      注意:(?m)只有在正则表达式中涉及到多行的“^”和“$”的匹配时,才使用Multiline模式。
      上面的匹配模式可以组合使用,比如(?is),(?im)。
      另外,还可以用(?i:exp)或者(?i)exp(?-i)来指定匹配的有效范围。

  • 相关阅读:
    拖拽模块move2
    拖拽模块move1
    String类和StringBuilder
    你真的会二分查找吗
    C++中关于new及动态内存分配的思考
    【转】Github 上传代码
    HDU4801·二阶魔方
    POJ2676,HDU4069解决数独的两种实现:DFS、DLX
    读书笔记
    SpringBoot-------实现多数据源Demo
  • 原文地址:https://www.cnblogs.com/gisblogs/p/3957882.html
Copyright © 2011-2022 走看看