今天做項目的時候遇到這樣一個需求,需要在網頁上展示今日黃曆資訊,資料格式如下
- 公曆時間: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
另外還有很多強大的功能水準有限就不一一列舉了,感興趣的可以參照官網文檔,也歡迎交流指正。新技能get起來!