今天做項目的時候遇到這樣一個需求,需要在網頁上展示今日黃歷信息,數據格式如下
主要包括公歷/農歷日期,以及忌宜信息的等。但是手裡並沒有現成的數據可供使用,怎麼辦呢?
革命前輩曾經說過,沒有槍,沒有炮,敵(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
另外還有很多強大的功能水平有限就不一一列舉了,感興趣的可以參照官網文檔,也歡迎交流指正。新技能get起來!
本文版權歸作者及博客園所有,轉載請注明作者及原文出處
溯源blog http://www.cnblogs.com/lkxsnow/