Java爬蟲入門簡介(三) —— Jsoup解析HTML頁面
上一篇部落格我們已經介紹瞭如何使用HttpClient模擬客戶端請求頁面了。這一篇部落格我們將描述如何解析獲取到的頁面內容。
上一節我們獲取了 http://www.datalearner.com/blog_list 頁面的HTML原始碼,但是這些原始碼是提供給瀏覽器解析用的,我們需要的資料其實是頁面上部落格的標題、作者、簡介、釋出日期等。我們需要通過一種方式來從HTML原始碼中解析出這類資訊並提取,然後存到文字或者資料庫之中。在這篇部落格中,我們將介紹使用Jsoup包幫助我們解析頁面,提取資料。
Jsoup是一款Java的HTML解析器,可以直接解析某個URL地址,也可以解析HTML內容。其主要的功能包括解析HTML頁面,通過DOM或者CSS選擇器來查詢、提取資料,可以更改HTML內容。Jsoup的使用方式也很簡單,使用Jsoup.parse(String str)方法將之前我們獲取到的HTML內容進行解析得到一個Documend類,剩下的工作就是從Document中選擇我們需要的資料了。舉個例子,假設我們有個HTML頁面的內容如下:
<html>
<divid="blog_list">
<divclass="blog_title">
<ahref="url1">第一篇部落格</a>
</div>
<divclass="blog_title">
<ahref="url2">第二篇部落格</a>
</div>
<divclass="blog_title">
<ahref="url3">第三篇部落格</a>
</div>
</div>
</html>
通過Jsoup我們可以把上面的三篇部落格的標題提取到一個List中。使用方法如下:
首先,我們通過maven把Jsoup引入進來
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.3</version>
</dependency>
然後編寫Java進行解析。
package org.hfutec.example;
import org.jsoup.Jsoup;
import
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
publicclassDataLearnerCrawler{
publicstaticvoid main(String[] args){
List<String> titles =newArrayList<String>();
List<String> urls =newArrayList<String>();
//假設我們獲取的HTML的字元內容如下
String html ="<html><div id=\"blog_list\"><div class=\"blog_title\"><a href=\"url1\">第一篇部落格</a></div><div class=\"blog_title\"><a href=\"url2\">第二篇部落格</a></div><div class=\"blog_title\"><a href=\"url3\">第三篇部落格</a></div></div></html>";
//第一步,將字元內容解析成一個Document類
Document doc =Jsoup.parse(html);
//第二步,根據我們需要得到的標籤,選擇提取相應標籤的內容
Elements elements = doc.select("div[id=blog_list]").select("div[class=blog_title]");
for(Element element : elements ){
String title = element.text();
titles.add(title);
urls.add(element.select("a").attr("href"));
}
//輸出測試
for(String title : titles ){
System.out.println(title);
}
for(String url : urls ){
System.out.println(url);
}
}
}
我們簡單說明一下Jsoup的解析過程。首先第一步都是呼叫parse()方法將字元物件變成一個Document物件,然後我們對這個物件進行操作。一般提取資料就是根據標籤選擇資料,使用select()方法語法格式和 javascript/css 選擇器都是一樣的。一般都是提取某個標籤,其屬性值為指定內容。得到的結果是一個Element的集合,為Elements(因為符合條件的標籤可能很多,所以結果是一個集合)。select()方法可以一直進行下去,直到選擇到我們想要的標籤集合為止(注意,我們並不一定要按照標籤層級一級一級往下選,可以直接寫select()方法到我們需要的標籤的上一級,比如這裡的示例程式碼可以直接寫成 Elements elements = doc.select(“div[class=blog_title]”); 其效果是一樣的)。對於選擇到的Elements的集合,我們可以通過迴圈的方式提取每一個需要的資料,比如,我們需要拿到標籤的文字資訊,就可以使用text()方法,如果我們需要拿到對應的HTML屬性資訊,我們可以使用attr()方法。我們可以看到上述方法的輸出結果如下:
一個例項
我們接著上一個爬取資料學習官方網站部落格列表的例子講解一個例項。我們已經知道可以使用Jsoup來解析爬取到的HTML頁面內容。那麼如何檢視我們需要的內容對應的標籤呢?以Chrome瀏覽器為例,我們需要爬取 http://www.datalearner.com/blog_list 這個頁面的的部落格,首先用Chrome瀏覽器開啟這個網址,然後滑鼠右鍵單擊部落格的標題,點選“檢查”就可以得到HTML頁面了。如下圖所示。
圖2 右鍵單擊標題
圖3 點選所在元素的父級元素邊上的小三角,收起程式碼檢視
圖4 確認當前部落格的HTML程式碼的一致性
通過上述操作之後,我們已經可以看到,所有的部落格的標題等資訊都存在class=card的div裡面了。於是,我們只要關注這個標籤裡面的內容是如何組織的,就可以了。如下圖所示,我們需要的資訊所屬的標籤,通過點選小三角展開就能得到了。
因此,解析部落格列表的程式碼可以寫成如下形式了。
package org.hfutec.example;
import org.apache.http.HttpEntity;
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;
import java.io.IOException;
/*******
* created by DuFei at 2017.08.25 21:00
* web crawler example
* ******/
publicclassDataLearnerCrawler{
publicstaticvoid main(String[] args){
String url ="http://www.datalearner.com/blog_list";
String rawHTML =null;
try{
rawHTML = getHTMLContent(url);
}catch(IOException e){
e.printStackTrace();
}
//將當前頁面轉換成Jsoup的Document物件
Document doc =Jsoup.parse(rawHTML);
//獲取所有的部落格列表集合
Elements blogList = doc.select("div[class=card]");
//針對每個部落格內容進行解析,並輸出
for(Element element : blogList ){
String title = element.select("h4[class=card-title]").text();
String introduction = element.select("p[class=card-text]").text();
String author = element.select("span[class=fa fa-user]").text();
System.