• 使用java开源工具httpClient及jsoup抓取解析网页数据


    使用java开源工具httpClient及jsoup抓取解析网页数据

    今天做项目的时候遇到这样一个需求,需要在网页上展示今日黄历信息,数据格式如下

    •   公历时间:2016年04月11日 星期一
    •   农历时间:猴年三月初五
    •   天干地支:丙申年 壬辰月 癸亥日
    •   宜:求子 祈福 开光 祭祀 安床
    •   忌:玉堂(黄道)危日,忌出行

      主要包括公历/农历日期,以及忌宜信息的等。但是手里并没有现成的数据可供使用,怎么办呢?

    革命前辈曾经说过,没有枪,没有炮,敌(wang)人(luo)给我们造!网络上有很多现成的在线

    万年历应用可供使用,虽然没有现成接口,但是我们可以伸出手来,自己去拿。也就是所谓的数据

    抓取。

      这里介绍两个使用的工具,httpClient以及jsoup,简介如下:

     

      HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

      httpClient使用方法如下:

      1. 创建HttpClient对象。

      2. 创建请求方法的实例,并指定请求URL。

      3. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。

      4. 调用HttpResponse相关方法获取相应内容。

      5. 释放连接。

     

      jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

     

      需要更多信息可以参见官网

      httpClient:http://hc.apache.org/httpcomponents-client-5.0.x/index.html

      jsoup:http://jsoup.org/

      

      接下来我们直接上代码,这里我们抓取2345在线万年历的数据 http://tools.2345.com/rili.htm

      首先我们定义一个实体类Almanac来存储黄历数据

      Almanac.java

    复制代码
     1 package com.likx.picker.util.bean;  2   3 /**  4  * 万年历工具实体类  5  *   6  * @author 溯源blog  7  * 2016年4月11日  8  */  9 public class Almanac { 10     private String solar;        /* 阳历 e.g.2016年 4月11日 星期一 */ 11     private String lunar;        /* 阴历 e.g. 猴年 三月初五*/ 12     private String chineseAra;    /* 天干地支纪年法 e.g.丙申年 壬辰月 癸亥日*/ 13     private String should;        /* 宜e.g. 求子 祈福 开光 祭祀 安床*/ 14     private String avoid;        /* 忌 e.g. 玉堂(黄道)危日,忌出行*/ 15  16     public String getSolar() { 17         return solar; 18     } 19  20     public void setSolar(String date) { 21         this.solar = date; 22     } 23  24     public String getLunar() { 25         return lunar; 26     } 27  28     public void setLunar(String lunar) { 29         this.lunar = lunar; 30     } 31  32     public String getChineseAra() { 33         return chineseAra; 34     } 35  36     public void setChineseAra(String chineseAra) { 37         this.chineseAra = chineseAra; 38     } 39  40     public String getAvoid() { 41         return avoid; 42     } 43  44     public void setAvoid(String avoid) { 45         this.avoid = avoid; 46     } 47  48     public String getShould() { 49         return should; 50     } 51  52     public void setShould(String should) { 53         this.should = should; 54     } 55  56     public Almanac(String solar, String lunar, String chineseAra, String should, 57             String avoid) { 58         this.solar = solar; 59         this.lunar = lunar; 60         this.chineseAra = chineseAra; 61         this.should = should; 62         this.avoid = avoid; 63     } 64 }
    复制代码

     

      然后是抓取解析的主程序,写程序之前需要在官网下载需要的jar包

      AlmanacUtil.java

    复制代码
    package com.likx.picker.util; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date;  import org.apache.http.HttpEntity; import org.apache.http.ParseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; /**  *<STRONG>类描述</STRONG> :  2345万年历信息爬取工具<p>  *     * @version 1.0 <p>  * @author 溯源blog  *   * <STRONG>创建时间</STRONG> : 2016年4月11日 下午14:15:44<p>  * <STRONG>修改历史</STRONG> :<p>  *<pre>  * 修改人                   修改时间                     修改内容  * ---------------         -------------------         -----------------------------------  *</pre>  */ public class AlmanacUtil {          /**      * 单例工具类      */     private AlmanacUtil() {     }     /**      * 获取万年历信息      * @return      */     public static Almanac getAlmanac(){         String url="http://tools.2345.com/rili.htm";         String html=pickData(url);         Almanac almanac=analyzeHTMLByString(html);         return almanac;     }          /*      * 爬取网页信息      */     private static String pickData(String url) {         CloseableHttpClient httpclient = HttpClients.createDefault();         try {             HttpGet httpget = new HttpGet(url);             CloseableHttpResponse response = httpclient.execute(httpget);             try {                 // 获取响应实体                 HttpEntity entity = response.getEntity();                 // 打印响应状态                 if (entity != null) {                     return EntityUtils.toString(entity);                 }             } finally {                 response.close();             }         } catch (ClientProtocolException e) {             e.printStackTrace();         } catch (ParseException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         } finally {             // 关闭连接,释放资源             try {                 httpclient.close();             } catch (IOException e) {                 e.printStackTrace();             }         }         return null;     }          /*      * 使用jsoup解析网页信息      */     private static Almanac analyzeHTMLByString(String html){         String solarDate,lunarDate,chineseAra,should,avoid=" ";         Document document = Jsoup.parse(html);         //公历时间         solarDate=getSolarDate();         //农历时间         Element eLunarDate=document.getElementById("info_nong");         lunarDate=eLunarDate.child(0).html().substring(1,3)+eLunarDate.html().substring(11);         //天干地支纪年法         Element eChineseAra=document.getElementById("info_chang");         chineseAra=eChineseAra.text().toString();             //         should=getSuggestion(document,"yi");         //         avoid=getSuggestion(document,"ji");         Almanac almanac=new Almanac(solarDate,lunarDate,chineseAra,should,avoid);         return almanac;     }     /*      * 获取忌/宜      */     private static String getSuggestion(Document doc,String id){         Element element=doc.getElementById(id);         Elements elements=element.getElementsByTag("a");         StringBuffer sb=new StringBuffer();         for (Element e : elements) {             sb.append(e.text()+" ");         }         return sb.toString();     }      /*      * 获取公历时间,用yyyy年MM月dd日 EEEE格式表示。      * @return yyyy年MM月dd日 EEEE      */     private static String getSolarDate() {         Calendar calendar = Calendar.getInstance();         Date solarDate = calendar.getTime();         SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 EEEE");         return formatter.format(solarDate);     }  }
    复制代码

     

      为了简单明了我把抓取解析抽象成了几个独立的方法,

      其中pickData()方法使用httpClient来抓取数据到一个字符串中(就是在网页上点击查看源代码看到的HTML源码),

    analyzeHTMLByString()方法来解析抓取到的字符串,getSuggestion方法把抓取方法类似的宜忌数据抽象到了

    一起,另外因为公历时间可以很容易的自己生成就没有在网页上爬取。

     

      然后下面是一个测试类简单测试下效果:

     AlmanacUtilTest.java

    复制代码
    package com.likx.picker.util.test;  public class AlmanacUtilTest {          public static void main(String args[]){         Almanac almanac=AlmanacUtil.getAlmanac();         System.out.println("公历时间:"+almanac.getSolar());         System.out.println("农历时间:"+almanac.getLunar());         System.out.println("天干地支:"+almanac.getChineseAra());         System.out.println("宜:"+almanac.getShould());         System.out.println("忌:"+almanac.getAvoid());     } }
    复制代码

     

      运行结果如下:

     

      集成到实际项目中效果是这样的:

     

      

     

      另外最近博客一直没怎么更新,因为最近考虑到技术氛围的原因,离开了对日外包行业,前往

    一家互联网公司就职。说一下最近的感受,那就是一个程序员最核心的竞争力不是学会了多少框架,

    掌握多少种工具(当然这些对于程序员也不可或缺),而是扎实的基础以及快速学习的能力,比如今天

    这个项目,从对httpClient,jsoup工具一无所知到编写出Demo代码总计大概1个多小时,在之前对于

    我来说是不可想象的,在技术氛围浓厚的地方快速get技能的感觉,非常好。

      当然本例只是一个非常浅显的小例子,网页上内容也很容易抓取,httpClient及jsoup工具更多强大

    的地方没有体现到,比如httpClient不仅可以发送get请求,而且可以发送post请求,提交表单,传送

    文件,还比如jsoup最强大的地方在于它支持仿jquery的选择器。本例仅仅使用了最简单的document.getElementById()

    匹配元素,实际上jsoup的选择器异常强大,可以说它就是java版的jquery,比如这样:

     

    Elements links = doc.select("a[href]"); // a with href Elements pngs = doc.select("img[src$=.png]");   // img with src ending .png Element masthead = doc.select("div.masthead").first();   // div with class=masthead Elements resultLinks = doc.select("h3.r > a"); // direct a after h3

     

     

  • 相关阅读:
    Java静态类
    【Java TCP/IP Socket】深入剖析socket——TCP套接字的生命周期
    【Java TCP/IP Socket】深入剖析socket——TCP通信中由于底层队列填满而造成的死锁问题(含代码)
    【Java TCP/IP Socket】深入剖析socket——数据传输的底层实现
    【Java TCP/IP Socket】基于NIO的TCP通信(含代码)
    【Java TCP/IP Socket】Java NIO Socket VS 标准IO Socket
    【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)
    数据结构课后练习题(练习三)7-5 Tree Traversals Again (25 分)
    快速排序详解(lomuto划分快排,hoare划分快排,classic经典快排,dualpivot双轴快排源码)
    Java多线程(一)——线程基础和锁锁锁
  • 原文地址:https://www.cnblogs.com/jing1617/p/7503945.html
Copyright © 2020-2023  润新知