关于方案

网上常用的方案有如下几种:
1. 根据解析dom结构,利用标签的特性来获取。比如titile,h1一般表示标题,p一般大多数在正文。去计算的时候可以去设置一些权重的方案,比方说div下包含p +1分,包含li减分等等。
2. 根据文字密度的来获取正文部分。这种方案是剔除html的tag标签,然后去计算文字密度,提取文字密度最高的部分。
3. 根据图像处理技术,来获取正文。


最开始,我采用了第2种方案,正确率有80%,但方案的缺点有如下
1. 有些网站正文只有一小段话,密度不高
2. 会丢失文章的排版、图片。

于是就启用了第一种方案,根据dom结构,算出正文最可能存在的div是哪一块。原先的思路是获取id或者class带有article属性的div,但是几乎每个网站的内容标签属性都不一致。后来根据多个网页的观察发现,现在大部分的网站正文部分都包含p标签,我们只需要找到包含最多p标签的那个最近的div就可以了。

内容获取的思路

获取dom中所有的p元素,向外找到其最近的div,计算命中最多次的div。
主要代码块如下:

public String analysisContent(){
        // 寻找dom下所有的p元素
        Elements ps = dom.select("p");
        HashMap<Object, Integer> map = new HashMap<Object, Integer>();
        // 输出div
        Element mostDiv = null;
        int max = 0;
        // 遍历所有的p元素
        La: for (Element element : ps) {
            Element parent = element;
            boolean isFind = false;
            // p元素向外找3层div,如果有,放到map里
            for (int i = 0; i < 3; i++) {
                parent = parent.parent();
                if (i == 0 && parent.is("a,li")) {// a和li一般是类目元素,该p元素不要
                    continue La;
                }
                if (parent.is("div")) {
                    isFind = true;
                    break;
                }
            }
            if (!isFind) {
                continue;
            }
            if (map.get(parent) == null) {
                map.put(parent, 1);
            } else {
                map.put(parent, map.get(parent) + 1);
            }
            // 从map里获取命中最多次的div
            if (max < map.get(parent)) {
                max = map.get(parent);
                mostDiv = parent;
            }
        }
        return mostDiv.toString();
    }

这里的dom主要是用到了jsoup,这是一个类似jquery的dom解析框架。经过多个网站的测试,正确率可以达到90%。如果不需要dom中的一些image、object、video等元素,单独再对该div做相应的处理就可以了。

提取文章标题

标题一般都是h1元素,这里我们找到h1元素,就认为是文章的标题,如果找不到h1,就取title标签的内容

public String analysisTitle() {
        Elements eles = dom.select("h1");
        if (eles != null && eles.size() > 0) {
            return eles.eq(0).text();
        }

        eles = dom.select("title");
        if (eles != null && eles.size() > 0) {
            return eles.eq(0).text();
        }
        return null;
    }
获取文章发布时间

这里我是直接用正则匹配的方式获取年月日,暂时没有想到更好的方案,正则如下:
“\d{4}[-|/|\|年]\d{1,2}[-|/|\|月]\d{1,2}[日]?”

到这里,文章的大致内容就全部获取到了,随便解析一片文章试试水


 <br>
 <!-- AD200x300_2 --> 
 <div class="gg200x300"> 
  <div style="position:relative;"> 
   <a href="http://gb.corp.163.com/gb/legal.html" class="ad_hover_href"></a> 
   <iframe src="http://g.163.com/r?site=netease&affiliate=news&cat=article&type=logo300x250&location=12" width="300" height="250" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"> </iframe> 
  </div> 
 </div>
 <p></p>
 <pre datatype="specialtag" datavalue="推荐" style="white-space:pre-wrap;display: block;border: 3px solid blue;" title="推荐"><p><a href="http://news.163.com/17/0124/01/CBGRQ23D00018AOP.html" target="_self" style="line-height: 1;">西安火车站"黑票点":自制白条车票非法营运跑长途</a></p><p>车票,既是乘客乘车的凭证,更是乘客维权的保证。然而,一些黑票点仅出具一张自制车票,就能让乘客乘坐非营运大巴车。面对检查,他们如何逃避?非营运车或手续不全的车辆又是如何将自己“洗白”,并堂而皇之地“营运”。近半个月来,记者在西安火车站广场及其附近进行了暗访。</p></pre> 
 <p></p> 
 <div class="ep-source cDGray"> 
  <span class="left"><a href="http://news.163.com/"><img src="http://img1.cache.netease.com/cnews/css13/img/end_news.png" alt="胡淑丽" width="13" height="12" class="icon"></a> 本文来源:金羊网-新快报 </span> 
  <!--杨强_NN6027-->
  <span class="ep-editor">责任编辑:杨强_NN6027</span> 
 </div> 
</div>
解析时间:236