免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3778 | 回复: 1
打印 上一主题 下一主题

用java开发一个搜索导航网站(三) 抽取正文 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-18 23:41 |只看该作者 |倒序浏览
  首先感谢chinaunix保留我的文章!

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

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

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

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

  接下来,有一个很重要的问题,那段最长的正文在哪里呢?
  肯定是在一个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
     这个是正文里混有图片和表格.


  为了感谢chinaunix保留我的帖子,感谢大家看我的帖子.我把抽取正文的部分代码和大家共享.这些代码基本解决了我在
上面列举出来的问题。包括正文中混有图片,连接,粗体,表格等。大家要是有兴趣可以改造下这些代码,完整的代码在附件中
代码中有全部的抽取算法.你可以新建个项目导入这些类,稍微调整下,就可以运行.其中有个字串替换函数,这个我没有加,诸位可以自己
随便找个这样的函数.你可以用我提供的代码试验下,看看抽取的效果如何.其中ExtractContext是程序执行的入口.context.vm是我定义的生成正文的摸版.你可以自己定义喜欢的格式.

    请大家重点看protected List extractHtml(Node nodeP, PageContext context, String siteUrl)
     这个函数是正文抽取的入口。我的这些函数写的不是很规范,别笑话!
   
    最后,有几句话想说下,我看到有个评论说我是个AD广告贴,我对这种看法表示理解,从客观的角度说,我写这帖子
既是和大家分享一些思路,同时自然也是在为自己的思路做个宣传。如果双方都有所收益,那也不是什么坏事情。难道你喜欢研究半天
然后默默无闻的藏起来吗?互联网是个开放的平台,应该要能包容一切不同的做法,理念。尤其是我们这些没日没夜辛苦做技术的人。
我办这个网站的初衷一方面是想把自己的那点点技术发挥出作用来,找出一些好的IT网站和大家分享。另一方面也是想能使自己或
者帮助其他的程序员开拓下视野和思路。

    我感谢CHINAUNIX的管理员保留我的帖子,我相信有容乃大!
   

/     /**
    * 递归钻取正文信息 --- 详细见附件
    * @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;
    }

     

正文抽取.rar

5.87 KB, 下载次数: 326

论坛徽章:
0
2 [报告]
发表于 2007-12-26 18:15 |只看该作者
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

本人最近也在做提取,感觉自己做的效果不如您的好,就想研究一下,可是上面这两个是什么,怎么找不到呢,你是不是用htmlparser还是nekohtml?急判回复
邮箱:buptisc_fh@yahoo.com.cn
谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP