`
gstarwd
  • 浏览: 1538311 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

用htmlparser分析并抽取正文

阅读更多

我这次要介绍的是如何抽取正文,这部分是最为核心的.因为如果不能很好的提取原有文章的内容和样式,那么搜索出来的东西
就会惨不忍睹.根本就没有使用价值

  在做正文抽取模块之前我曾经参考过很多抽取模式,有配置模版的,有搞视觉匹配的.有搞关键字识别的.我挨个做了分析
首先配置摸版是不太现实的,因为我在搜索技术资讯的时候,根本不知道会搜索到哪个网站,也根本没精力去配置摸版.所以这个行不通
  
  基于视觉效果的分析,这个难度比较大,而且只适合于规范的网站,而现在很多网站根本不规范,广告链接漫天飞.人家都把最好的
位置留给广告了.而且我一直怀疑这个模式的可行性,它只是一个善意的推测.所以这方面没做过多尝试

  我在想,是否有种简单的方法呢?难道就没有什么共性吗?

  我想所有的正文应该有个共同的特点,那就是正文的长度应该超过其他文字组合的长度.很少会有一句话的正文,很少会有长度
短于标题的正文.所以这个应该成为一个突破口.

  接下来,有一个很重要的问题,那段最长的正文在哪里呢?
  肯定是在一个TABLE,或者DIV,或者ParagraphTag里.那好,那就找到那个包含文字最多的DIV或者TABLE.

  不过问题又来了,HTML页面,经常是HTML元素的长度超过了正文的长度,有时候混入了不少的JAVASCRIPT.这些元素
HTMLPARSER经常会误认为是正文加以识别,导致很多正文竟然是一段JAVASCRIPT.
  祛除杂质是一个关键,这里面要把那些HTML中常用的标签,以及连接中正文去除掉,否则,你搜索出来的很可能是别的什么,尤其
当正文文字相对较少的时候.我在搜索SOHU页面的时候就经常遇到这个问题,原因是SOHU的页面不是严格按照DIV布局,里面有很多广告
的JAVASCRIPT。新浪的有些页面也有这个现象,反到是一些中小网站的布局很规范,呵呵,真奇怪了。

  做完这些工作后,我发现仍然有些网页不能正常抓取,原因是HTMLPARSER对TEXT的认识有问题.例如一段文字在
ParagraphTag中或者span中包含的,就不能很好的识别.所以要单独做个抽取ParagraphTag内容的函数.

  做完这些步骤后,有一个问题出来了就是正文中包含的图片,连接,粗体,正常的表格.这些问题一个个的冒出来.既然问题出来了
那就要一个个的解决.解决了这些难题.我的网站抓取文章的质量就大大的提高了85%的准确率,基本达到实用阶段.我网站上的正文快照基本和原文保 持一致.

    提供几个例子,大家可以看下原文和我抓取的有多少不同
    1. http://www.itsubway.com/context/20071218/11762.htm
                这个是单纯获取正文的例子,其中有粗体标签和链接

    2 http://www.itsubway.com/context/20071218/12041.htm
     这个是正文里混有图片和表格.


  我把抽取正文的部分代码和大家共享.这些代码基本解决了我在上面列举出来的问题。包括正文中混有图片,连接,粗体,表格等。
    大家要是有兴趣可以改造下这些代码 请大家重点看protected List extractHtml(Node nodeP, PageContext context, String siteUrl)
    这个函数是正文抽取的入口。我的这些函数写的不是很规范,别笑话!
   
   
   

/**
    * 收集HTML页面信息 调用抓取函数 按照自己的摸版 生成网页
    * @param url
    * @param urlEncode
    */
    public void makeContext(ChannelLinkDO c) {
        String metakeywords = "<META content={0} name=keywords>";
        String metatitle = "<TITLE>{0}</TITLE>";
        String metadesc = "<META content={0} name=description>";
        String netshap = "<p> 正文快照: 时间{0}</p> ";

        String tempLeate = "<LI class=active><A href=\"{0}\" target=_blank>{1}</A></LI>";
        String crop = "<p><A href=\"{0}\" target=_blank>{1}</A></p> ";

        try {
            String siteUrl = getLinkUrl(c.getLink());
            Parser parser = new Parser(c.getLink());
            parser.setEncoding(c.getEncode());

            for (NodeIterator e = parser.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                if (node instanceof Html) {
                    PageContext context = new PageContext();
                    context.setNumber(0);
                    context.setTextBuffer(new StringBuffer());
                    //抓取出内容
                    extractHtml(node, context, siteUrl);

                    StringBuffer testContext = context.getTextBuffer();
                    //.....生成网页
                    }
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    private String getLinkUrl(String link) {
        String urlDomaiPattern = "(http://[^/]*? " + "/)(.*?)";

        Pattern pattern = Pattern.compile(urlDomaiPattern,
                Pattern.CASE_INSENSITIVE + Pattern.DOTALL);
        Matcher matcher = pattern.matcher(link);
        String url = "";

        while (matcher.find()) {
            int start = matcher.start(1);
            int end = matcher.end(1);

            url = link.substring(start, end - 1).trim();
        }

        return url;
    }

    /**
    * 递归钻取正文信息
    * @param nodeP
    * @return
    */
    protected List extractHtml(Node nodeP, PageContext context, String siteUrl)
        throws Exception {
        NodeList nodeList = nodeP.getChildren();
        boolean bl = false;

        if ((nodeList == null) || (nodeList.size() == 0)) {
            if (nodeP instanceof ParagraphTag) {
                ArrayList tableList = new ArrayList();
                StringBuffer temp = new StringBuffer();
                temp.append("<p style=\"TEXT-INDENT: 2em\">");
                tableList.add(temp);
                temp = new StringBuffer();
                temp.append("</p>").append(lineSign);
                tableList.add(temp);

                return tableList;
            }

            return null;
        }

        if ((nodeP instanceof TableTag) || (nodeP instanceof Div)) {
            bl = true;
        }

        if (nodeP instanceof ParagraphTag) {
            ArrayList tableList = new ArrayList();
            StringBuffer temp = new StringBuffer();
            temp.append("<p style=\"TEXT-INDENT: 2em\">");
            tableList.add(temp);
            extractParagraph(nodeP, siteUrl, tableList);

            temp = new StringBuffer();
            temp.append("</p>").append(lineSign);

            tableList.add(temp);

            return tableList;
        }

        ArrayList tableList = new ArrayList();

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                if (node instanceof LinkTag) {
                    tableList.add(node);
                    setLinkImg(node, siteUrl);
                } else if (node instanceof ImageTag) {
                    ImageTag img = (ImageTag) node;

                    if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
                        img.setImageURL(siteUrl + img.getImageURL());
                    } else {
                        img.setImageURL(img.getImageURL());
                    }

                    tableList.add(node);
                } else if (node instanceof ScriptTag ||
                        node instanceof StyleTag || node instanceof SelectTag) {
                } else if (node instanceof TextNode) {
                    if (node.getText().length() > 0) {
                        StringBuffer temp = new StringBuffer();
                        String text = collapse(node.getText()
                                                   .replaceAll("&nbsp;", "")
                                                   .replaceAll(" ", ""));

                        temp.append(text.trim());

                        tableList.add(temp);
                    }
                } else {
                    if (node instanceof TableTag || node instanceof Div) {
                        TableValid tableValid = new TableValid();
                        isValidTable(node, tableValid);

                        if (tableValid.getTrnum() > 2) {
                            tableList.add(node);

                            continue;
                        }
                    }

                    List tempList = extractHtml(node, context, siteUrl);

                    if ((tempList != null) && (tempList.size() > 0)) {
                        Iterator ti = tempList.iterator();

                        while (ti.hasNext()) {
                            tableList.add(ti.next());
                        }
                    }
                }
            }
        } catch (Exception e) {
            return null;
        }

        if ((tableList != null) && (tableList.size() > 0)) {
            if (bl) {
                StringBuffer temp = new StringBuffer();
                Iterator ti = tableList.iterator();
                int wordSize = 0;
                StringBuffer node;
                int status = 0;
                StringBuffer lineStart = new StringBuffer(
                        "<p style=\"TEXT-INDENT: 2em\">");
                StringBuffer lineEnd = new StringBuffer("</p>" + lineSign);

                while (ti.hasNext()) {
                    Object k = ti.next();

                    if (k instanceof LinkTag) {
                        if (status == 0) {
                            temp.append(lineStart);
                            status = 1;
                        }

                        node = new StringBuffer(((LinkTag) k).toHtml());
                        temp.append(node);
                    } else if (k instanceof ImageTag) {
                        if (status == 0) {
                            temp.append(lineStart);
                            status = 1;
                        }

                        node = new StringBuffer(((ImageTag) k).toHtml());
                        temp.append(node);
                    } else if (k instanceof TableTag) {
                        if (status == 0) {
                            temp.append(lineStart);
                            status = 1;
                        }

                        node = new StringBuffer(((TableTag) k).toHtml());
                        temp.append(node);
                    } else if (k instanceof Div) {
                        if (status == 0) {
                            temp.append(lineStart);
                            status = 1;
                        }

                        node = new StringBuffer(((Div) k).toHtml());
                        temp.append(node);
                    } else {
                        node = (StringBuffer) k;

                        if (status == 0) {
                            if (node.indexOf("<p") < 0) {
                                temp.append(lineStart);
                                temp.append(node);
                                wordSize = wordSize + node.length();
                                status = 1;
                            } else {
                                temp.append(node);
                                status = 1;
                            }
                        } else if (status == 1) {
                            if (node.indexOf("</p") < 0) {
                                if (node.indexOf("<p") < 0) {
                                    temp.append(node);
                                    wordSize = wordSize + node.length();
                                } else {
                                    temp.append(lineEnd);
                                    temp.append(node);
                                    status = 1;
                                }
                            } else {
                                temp.append(node);
                                status = 0;
                            }
                        }
                    }
                }

                if (status == 1) {
                    temp.append(lineEnd);
                }

                if (wordSize > context.getNumber()) {
                    context.setNumber(wordSize);
                    context.setTextBuffer(temp);
                }

                return null;
            } else {
                return tableList;
            }
        }

        return null;
    }

    /**
    * 设置图象连接
    * @param nodeP
    * @param siteUrl
    */
    private void setLinkImg(Node nodeP, String siteUrl) {
        NodeList nodeList = nodeP.getChildren();

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                if (node instanceof ImageTag) {
                    ImageTag img = (ImageTag) node;

                    if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
                        img.setImageURL(siteUrl + img.getImageURL());
                    } else {
                        img.setImageURL(img.getImageURL());
                    }
                }
            }
        } catch (Exception e) {
            return;
        }

        return;
    }

    /**
    * 钻取段落中的内容
    * @param nodeP
    * @param siteUrl
    * @param tableList
    * @return
    */
    private List extractParagraph(Node nodeP, String siteUrl, List tableList) {
        NodeList nodeList = nodeP.getChildren();

        if ((nodeList == null) || (nodeList.size() == 0)) {
            if (nodeP instanceof ParagraphTag) {
                StringBuffer temp = new StringBuffer();
                temp.append("<p style=\"TEXT-INDENT: 2em\">");
                tableList.add(temp);
                temp = new StringBuffer();
                temp.append("</p>").append(lineSign);
                tableList.add(temp);

                return tableList;
            }

            return null;
        }

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                if (node instanceof ScriptTag || node instanceof StyleTag ||
                        node instanceof SelectTag) {
                } else if (node instanceof LinkTag) {
                    tableList.add(node);
                    setLinkImg(node, siteUrl);
                } else if (node instanceof ImageTag) {
                    ImageTag img = (ImageTag) node;

                    if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
                        img.setImageURL(siteUrl + img.getImageURL());
                    } else {
                        img.setImageURL(img.getImageURL());
                    }

                    tableList.add(node);
                } else if (node instanceof TextNode) {
                    if (node.getText().trim().length() > 0) {
                        String text = collapse(node.getText()
                                                   .replaceAll("&nbsp;", "")
                                                   .replaceAll(" ", ""));
                        StringBuffer temp = new StringBuffer();
                        temp.append(text);
                        tableList.add(temp);
                    }
                } else if (node instanceof Span) {
                    StringBuffer spanWord = new StringBuffer();
                    getSpanWord(node, spanWord);

                    if ((spanWord != null) && (spanWord.length() > 0)) {
                        String text = collapse(spanWord.toString()
                                                       .replaceAll("&nbsp;", "")
                                                       .replaceAll(" ", ""));

                        StringBuffer temp = new StringBuffer();
                        temp.append(text);
                        tableList.add(temp);
                    }
                } else if (node instanceof TagNode) {
                    String tag = node.toHtml();

                    if (tag.length() <= 10) {
                        tag = tag.toLowerCase();

                        if ((tag.indexOf("strong") >= 0) ||
                                (tag.indexOf("b") >= 0)) {
                            StringBuffer temp = new StringBuffer();
                            temp.append(tag);
                            tableList.add(temp);
                        }
                    } else {
                        if (node instanceof TableTag || node instanceof Div) {
                            TableValid tableValid = new TableValid();
                            isValidTable(node, tableValid);

                            if (tableValid.getTrnum() > 2) {
                                tableList.add(node);

                                continue;
                            }
                        }

                        extractParagraph(node, siteUrl, tableList);
                    }
                }
            }
        } catch (Exception e) {
            return null;
        }

        return tableList;
    }

    protected void getSpanWord(Node nodeP, StringBuffer spanWord) {
        NodeList nodeList = nodeP.getChildren();

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                if (node instanceof ScriptTag || node instanceof StyleTag ||
                        node instanceof SelectTag) {
                } else if (node instanceof TextNode) {
                    spanWord.append(node.getText());
                } else if (node instanceof Span) {
                    getSpanWord(node, spanWord);
                } else if (node instanceof ParagraphTag) {
                    getSpanWord(node, spanWord);
                } else if (node instanceof TagNode) {
                    String tag = node.toHtml().toLowerCase();

                    if (tag.length() <= 10) {
                        if ((tag.indexOf("strong") >= 0) ||
                                (tag.indexOf("b") >= 0)) {
                            spanWord.append(tag);
                        }
                    }
                }
            }
        } catch (Exception e) {
        }

        return;
    }

    /**
    * 判断TABLE是否是表单
    * @param nodeP
    * @return
    */
    private void isValidTable(Node nodeP, TableValid tableValid) {
        NodeList nodeList = nodeP.getChildren();

        /**如果该表单没有子节点则返回**/
        if ((nodeList == null) || (nodeList.size() == 0)) {
            return;
        }

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                /**如果子节点本身也是表单则返回**/
                if (node instanceof TableTag || node instanceof Div) {
                    return;
                } else if (node instanceof ScriptTag ||
                        node instanceof StyleTag || node instanceof SelectTag) {
                    return;
                } else if (node instanceof TableColumn) {
                    return;
                } else if (node instanceof TableRow) {
                    TableColumnValid tcValid = new TableColumnValid();
                    tcValid.setValid(true);
                    findTD(node, tcValid);

                    if (tcValid.isValid()) {
                        if (tcValid.getTdNum() < 2) {
                            if (tableValid.getTdnum() > 0) {
                                return;
                            } else {
                                continue;
                            }
                        } else {
                            if (tableValid.getTdnum() == 0) {
                                tableValid.setTdnum(tcValid.getTdNum());
                                tableValid.setTrnum(tableValid.getTrnum() + 1);
                            } else {
                                if (tableValid.getTdnum() == tcValid.getTdNum()) {
                                    tableValid.setTrnum(tableValid.getTrnum() +
                                        1);
                                } else {
                                    return;
                                }
                            }
                        }
                    }
                } else {
                    isValidTable(node, tableValid);
                }
            }
        } catch (Exception e) {
            return;
        }

        return;
    }

    /**
    * 判断是否有效TR
    * @param nodeP
    * @param TcValid
    * @return
    */
    private void findTD(Node nodeP, TableColumnValid tcValid) {
        NodeList nodeList = nodeP.getChildren();

        /**如果该表单没有子节点则返回**/
        if ((nodeList == null) || (nodeList.size() == 0)) {
            return;
        }

        try {
            for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
                Node node = (Node) e.nextNode();

                /**如果有嵌套表单**/
                if (node instanceof TableTag || node instanceof Div ||
                        node instanceof TableRow ||
                        node instanceof TableHeader) {
                    tcValid.setValid(false);

                    return;
                } else if (node instanceof ScriptTag ||
                        node instanceof StyleTag || node instanceof SelectTag) {
                    tcValid.setValid(false);

                    return;
                } else if (node instanceof TableColumn) {
                    tcValid.setTdNum(tcValid.getTdNum() + 1);
                } else {
                    findTD(node, tcValid);
                }
            }
        } catch (Exception e) {
            tcValid.setValid(false);

            return;
        }

        return;
    }

    protected String collapse(String string) {
        int chars;
        int length;
        int state;
        char character;
        StringBuffer buffer = new StringBuffer();
        chars = string.length();

        if (0 != chars) {
            length = buffer.length();
            state = ((0 == length) || (buffer.charAt(length - 1) == ' ') ||
                ((lineSign_size <= length) &&
                buffer.substring(length - lineSign_size, length).equals(lineSign)))
                ? 0 : 1;

            for (int i = 0; i < chars; i++) {
                character = string.charAt(i);

                switch (character) {
                case '\u0020':
                case '\u0009':
                case '\u000C':
                case '\u200B':
                case '\u00a0':
                case '\r':
                case '\n':

                    if (0 != state) {
                        state = 1;
                    }

                    break;

                default:

                    if (1 == state) {
                        buffer.append(' ');
                    }

                    state = 2;
                    buffer.append(character);
                }
            }
        }

        return buffer.toString();
    }

分享到:
评论

相关推荐

    HTMLParser抽取Web网页正文信息.doc

    ### HTMLParser抽取Web网页正文信息的关键知识点 #### 一、HTMLParser简介与应用 HTMLParser是一种用于解析HTML文档的工具,特别适用于从Web网页中提取有用的信息。它能够有效地识别和解析HTML标签,帮助开发者从...

    HTMLParser抽取Web网页正文信息

    HTMLParser 是一个强大的工具,用于解析和分析HTML文档,它能帮助我们从网页中抽取主要信息,排除掉无关的导航、广告和版权等噪音内容。这不仅能够优化用户体验,节省浏览时间,还能提高用户获取信息的效率,进而...

    基于HTMLParser的Web信息抽取系统的设计与实现

    信息抽取模块是系统的核心,它利用HTMLParser解析网页,并结合正则表达式进行模式匹配,以提取特定类型的信息。在本案例中,重点在于电子邮件地址的抽取。通过分析网页源代码,模块能够识别出符合电子邮件格式的字符...

    htmlparser进行网页信息的抽取

    HTMLParser 是一个强大的Java库,专门用于解析HTML文档并从中提取信息。在网页抓取和信息采集领域,HTMLParser 提供了高效的处理机制,能够帮助开发者有效地解析复杂的HTML结构,提取所需的数据。以下是对HTMLParser...

    基于HttpClient与HTMLParser 的网页正文提取

    3. 网页抓取和分析方法的实现:文章中提出的基于HttpClient与HTMLParser的网页抓取解析方法,结合了两者的优点,实现了快速且有效的网页内容抓取和正文提取。该方法能够针对特定的网页内容进行深入分析,并能够应对...

    HtmlParser提取网页信息的设计与实现

    本文将详细介绍如何利用HtmlParser这一开源工具来提取网页中的关键信息,并通过数据清洗将其存储到SQL数据库中,以便后续的数据分析和应用。 #### 二、HtmlParser概述 HtmlParser是一种轻量级、高效且易于使用的...

    基于统计的网页正文信息抽取

    在本案例中,使用了名为htmlparser的网页分析器。这是一个Java库,专门用于解析HTML文档,帮助开发者处理和操作HTML元素。通过htmlparser,我们可以方便地遍历HTML文档的DOM树,对每个节点进行分析,找出可能包含...

    HTMLparser

    这个压缩包“HTMLparser.rar”包含的源码可能是一个用特定编程语言(如Python、Java或JavaScript)实现的HTML解析器。通过分析HTML文档的结构,HTMLparser能够提取出所需的数据,比如标签、属性、文本内容等。 在...

    htmlParser详细文档

    - `HTMLParser抽取Web网页正文信息.doc`: 这份文档可能详细介绍了如何使用HTMLParser来提取网页正文内容,包括步骤和示例代码。 - `htmlparser文档.doc`: 这应是HTMLParser的官方或第三方文档,包含了API介绍、...

    HTMLParser-2.0-SNAPSHOT

    HTMLParser-2.0-SNAPSHOT 是一个针对Web信息抽取的软件包,它包含了多个核心组件,用于解析和处理HTML文档。...在实际应用中,用户可以根据项目需求,组合使用这些组件,构建适合自己的信息抽取系统。

    使用 HttpClient 和 HtmlParser 实现简易网络爬虫

    HtmlParser的特点包括过滤器、访问者模式、处理自定义标签以及使用JavaBeans的便利性。这个库被设计得既快速又健壮,适用于处理互联网上的实际网页。你可以在这里获取HtmlParser的最新版本、源码、API文档和JAR包:...

    用C#实现HtmlParser的代码

    该篇文章主要介绍了用C#实现HtmlParser的两种方法,分别是使用System.Net.WebClient下载网页并使用正则表达式来分析Html内容,以及使用Winista.Htmlparser.Net解析Html。下面我们将详细介绍这两种方法。 第一种方法...

    HTMLParser提取网页超链接研究

    1. **加载HTML文档**:使用HTMLParser加载待分析的HTML文档。 2. **定义过滤器**:根据需求定义过滤器来筛选出包含超链接的HTML元素。 3. **提取超链接**:遍历匹配到的HTML元素,提取出其中的超链接。 下面是一个...

    htmlparser 使用指南 入门 必读htmlparser 使用指南 入门 必读htmlparser 使用指南 入门 必读

    虽然在某些方面,如容错性和性能,NekoHTML可能更胜一筹,并且被HTMLUnit所采用,但HTMLParser的文档和测试用例相对更丰富,对于构建垂直搜索引擎的页面处理和分析需求,HTMLParser是一个不错的选择。 HTMLParser的...

    HtmlParser

    HTMLParser是一个用于解析HTML文档的库,它在编程领域中扮演着重要的角色,尤其是在处理网页内容和数据抓取时。...了解其工作原理和使用技巧,对于进行网页爬虫、数据分析或Web应用开发等任务具有重要意义。

    使用 HttpClient 和 HtmlParser 实现简易爬虫

    通过使用HtmlParser,开发者可以方便地抽取或转换网页内容。该项目在SourceForge上维护,具有丰富的特性,包括但不限于过滤器、访问者模式支持、自定义标签处理等。这些特性使得HtmlParser成为处理互联网上半结构化...

    HTMLParser资料

    在使用HTMLParser时,首先需要导入相关库,并创建一个解析器实例。接着,定义事件处理器,例如`StartTagHandler`和`EndTagHandler`,在遇到开始标签和结束标签时执行相应的方法。对于超链接,我们可以关注`&lt;a&gt;`标签...

    HTMLParser提取网页内容

    可以使用HTMLParser库提供的API来遍历DOM树,查找这些元素并获取其文本内容。 例如,对于标题提取,可以遍历HTML中的所有`&lt;h1&gt;`到`&lt;h6&gt;`标签,然后收集它们的文本;对于正文,可以寻找段落标签或其他可能包含正文...

Global site tag (gtag.js) - Google Analytics