Java 爬蟲工具Jsoup詳解
Java 爬蟲工具Jsoup詳解
Jsoup是一款 Java 的 HTML 解析器,可直接解析某個(gè) URL 地址、HTML 文本內(nèi)容。它提供了一套非常省力的 API,可通過 DOM,CSS 以及類似于 jQuery 的操作方法來取出和操作數(shù)據(jù)。
jsoup 的主要功能如下:
1. 從一個(gè) URL,文件或字符串中解析 HTML;
2. 使用 DOM 或 CSS 選擇器來查找、取出數(shù)據(jù);
3. 可操作 HTML 元素、屬性、文本;
jsoup 是基于 MIT 協(xié)議發(fā)布的,可放心使用于商業(yè)項(xiàng)目。
jsoup 可以從包括字符串、URL 地址以及本地文件來加載 HTML 文檔,并生成 Document 對(duì)象實(shí)例。
簡(jiǎn)單而言,Jsoup就是先取html頁面代碼然后解析這些頁面通過Jsoup攜帶的滿足我們絕大多數(shù)需求的各種選擇器從這個(gè)頁面中獲取我們所需要的重要數(shù)據(jù)的一款功能強(qiáng)大的html解析器,但也只是相對(duì)而言,這里的頁面這是死的靜態(tài)頁面,如果你想獲取動(dòng)態(tài)生成的頁面數(shù)據(jù)那么你得用到其他的java 爬蟲技術(shù),我會(huì)不定時(shí)更新這些技術(shù)一起探討。下面我們來具體談?wù)勅绾芜\(yùn)用Jsoup
一、如何取頁面
Jsoup提供了用來解析html頁面的方法 parse(),我們通過解析它可以獲取整個(gè)頁面的dom對(duì)象,通過這個(gè)對(duì)象來獲取你所需要的頁面所須有的參數(shù)。獲取頁面的方法有很多,這里就簡(jiǎn)單的列舉幾個(gè):
① 通過Jsoup攜帶的connect()方法
String htmlPage = Jsoup.connect("https://www.baidu.com").get().toString();
這個(gè)方法說需要的參數(shù)就是一個(gè)String類型的url鏈接,但是你的注意把這些鏈接的protrol加上,以免問題, 其實(shí)這個(gè)方法解決了我們很多問題,我們完全可以把Jsoup解析html抽取成一段通用工具類,然后通過改變拼接的url參數(shù)獲取到很多我們想要的東西,舉個(gè)例子:京東和淘寶的商品鏈接都是固定的,通過改變其三方商品ID來獲取商品詳情參數(shù)。
String url = "https://item.jd.com/11476104681.html"; 完全可以替換成 String url = "https://item.jd.com/"+skuId+".html";
通過改變他的三方商品ID你就可以獲取這個(gè)頁面一些基本數(shù)據(jù),像商品的圖片和標(biāo)題什么的都可以輕松獲取,而價(jià)格因?yàn)樽隽艘恍┫嚓P(guān)方面的處理得動(dòng)態(tài)的獲取,這里先不做說明,后面慢慢會(huì)講解。
②通過httpclient直接獲取這個(gè)頁面的靜態(tài)頁面
先貼一部分httpclient獲取頁面工具
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
/**
* HTTP請(qǐng)求工具類.
* @author LuoLong
* @since 20150513
*
*/
public class HttpClientUtils {
/**
* post方式請(qǐng)求.
* @param url 請(qǐng)求地址.
* @param params 請(qǐng)求參數(shù)
* @return String
*/
public static String post(String url, Map<String, String> params) {
DefaultHttpClient httpclient = new DefaultHttpClient();
String body = null;
HttpPost post = postForm(url, params);
body = invoke(httpclient, post);
httpclient.getConnectionManager().shutdown();
return body;
}
/**
* get方式請(qǐng)求.
* @param url 請(qǐng)求地址.
* @return String
*/
public static String get(String url) {
DefaultHttpClient httpclient = new DefaultHttpClient();
String body = null;
HttpGet get = new HttpGet(url);
body = invoke(httpclient, get);
httpclient.getConnectionManager().shutdown();
return body;
}
/**
* 請(qǐng)求方法.
* @param httpclient DefaultHttpClient.
* @param httpost 請(qǐng)求方式.
* @return String
*/
private static String invoke(DefaultHttpClient httpclient,
HttpUriRequest httpost) {
HttpResponse response = sendRequest(httpclient, httpost);
String body = paseResponse(response);
return body;
}
/**
*
* @param response
* @return
*/
@SuppressWarnings({ "deprecation", "unused" })
private static String paseResponse(HttpResponse response) {
HttpEntity entity = response.getEntity();
String charset = EntityUtils.getContentCharSet(entity);
String body = null;
try {
body = EntityUtils.toString(entity);
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return body;
}
private static HttpResponse sendRequest(DefaultHttpClient httpclient,
HttpUriRequest httpost) {
HttpResponse response = null;
try {
response = httpclient.execute(httpost);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
@SuppressWarnings("deprecation")
private static HttpPost postForm(String url, Map<String, String> params) {
HttpPost httpost = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
Set<String> keySet = params.keySet();
for (String key : keySet) {
nvps.add(new BasicNameValuePair(key, params.get(key)));
}
try {
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return httpost;
}
}
通過get()方法就可以獲取html頁面的String類型數(shù)據(jù)
String content = HttpClientUtils.get(url); 或者你可以直接把頁面下載到本地,然后解析此html文檔獲取 File input = new File(FilePath); Document doc = Jsoup.parse(input, "UTF-8", url);
二、解析頁面獲取需要的數(shù)據(jù)
當(dāng)你獲取到頁面的dom對(duì)象后,那么下面的操作就非常簡(jiǎn)單了,你只需要通過操作這個(gè)dom對(duì)象來獲取頁面所有的靜態(tài)資源,動(dòng)態(tài)加載的資源不在此列,后面在做講解。
先貼一段百度網(wǎng)頁的源代碼:
</form>
<div id="m"></div>
</div>
</div>
<div id="u">
<a class="toindex" href="/" rel="external nofollow" >百度首頁</a>
<a href="javascript:;" rel="external nofollow" name="tj_settingicon" class="pf">設(shè)置<i class="c-icon c-icon-triangle-down"></i></a>
<a rel="external nofollow" rel="external nofollow" name="tj_login" class="lb" onclick="return false;">登錄</a>
</div>
<div id="u1">
<a rel="external nofollow" name="tj_trnews" class="mnav">新聞</a>
<a rel="external nofollow" name="tj_trhao123" class="mnav">hao123</a>
<a rel="external nofollow" name="tj_trmap" class="mnav">地圖</a>
<a rel="external nofollow" name="tj_trvideo" class="mnav">視頻</a>
<a rel="external nofollow" name="tj_trtieba" class="mnav">貼吧</a>
<a rel="external nofollow" name="tj_trxueshu" class="mnav">學(xué)術(shù)</a>
<a rel="external nofollow" rel="external nofollow" name="tj_login" class="lb" onclick="return false;">登錄</a>
<a rel="external nofollow" name="tj_settingicon" class="pf">設(shè)置</a>
<a rel="external nofollow" name="tj_briicon" class="bri" style="display: block;">更多產(chǎn)品</a>
</div>
</div>
</div>
<div class="s_tab" id="s_tab">
<b>網(wǎng)頁</b>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'news'})">新聞</a>
<a rel="external nofollow" wdfield="kw" onmousedown="return c({'fm':'tab','tab':'tieba'})">貼吧</a>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'zhidao'})">知道</a>
<a rel="external nofollow" wdfield="key" onmousedown="return c({'fm':'tab','tab':'music'})">音樂</a>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'pic'})">圖片</a>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'video'})">視頻</a>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'map'})">地圖</a>
<a rel="external nofollow" wdfield="word" onmousedown="return c({'fm':'tab','tab':'wenku'})">文庫</a>
<a rel="external nofollow" onmousedown="return c({'fm':'tab','tab':'more'})">更多»</a>
</div>
<div class="qrcodeCon">
<div id="qrcode">
<div class="qrcode-item qrcode-item-1">
<div class="qrcode-img"></div>
<div class="qrcode-text">
<p><b>手機(jī)百度</b></p>
</div>
</div>
</div>
</div>
<div id="ftCon">
<div class="ftCon-Wrapper">
<div id="ftConw">
<p id="lh"><a id="setf" rel="external nofollow" onmousedown="return ns_c({'fm':'behs','tab':'favorites','pos':0})" target="_blank">把百度設(shè)為主頁</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about'})" rel="external nofollow" >關(guān)于百度</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_about_en'})" rel="external nofollow" >About Baidu</a><a onmousedown="return ns_c({'fm':'behs','tab':'tj_tuiguang'})" rel="external nofollow" >百度推廣</a></p>
<p id="cp">©2017 Baidu <a rel="external nofollow" onmousedown="return ns_c({'fm':'behs','tab':'tj_duty'})">使用百度前必讀</a> <a rel="external nofollow" class="cp-feedback" onmousedown="return ns_c({'fm':'behs','tab':'tj_homefb'})">意見反饋</a> 京ICP證030173號(hào) <i class="c-icon-icrlogo"></i> <a id="jgwab" target="_blank" rel="external nofollow" >京公網(wǎng)安備11000002000001號(hào)</a> <i class="c-icon-jgwablogo"></i></p>
</div>
</div>
</div>
<div id="wrapper_wrapper">
</div>
</div>
<div class="c-tips-container" id="c-tips-container"></div>
在貼上Jsoup自身攜帶的常用的幾個(gè)獲取dom對(duì)象具體元素的方法:
method description getElementsByClass() 通過Class屬性來定位元素,獲取的是所有帶這個(gè)class屬性的集合 getElementsByTag(); 通過標(biāo)簽名字來定位元素,獲取的是所有帶有這個(gè)標(biāo)簽名字的元素結(jié)合 getElementById(); 通過標(biāo)簽的ID來定位元素,這個(gè)是精準(zhǔn)定位,因?yàn)轫撁娴腎D基本不會(huì)重復(fù) getElementsByAttributeValue(); 通過屬性和屬性名來定位元素,獲取的也是一個(gè)滿足條件的集合; getElementsByAttributeValueMatching() 通過正則匹配屬性
比如說我現(xiàn)在要獲取百度首頁這個(gè)title,那么我們得先確定這玩意在哪,通過查看我們發(fā)現(xiàn)它是id=”u”的div標(biāo)簽的一個(gè)子元素,那么不管那么多我們先通過這個(gè)Id取到這個(gè)對(duì)象然后在獲取這個(gè)Title,下面是具體操作
//獲取頁面對(duì)象
String startPage="https://www.baidu.com";
Document document = Jsoup.connect(startPage).userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36").get();
//定位元素父級(jí)
Element parentElement = document.getElementById("u");
//定位具體元素
Element titleElement = parentElement.getElementsByTag("a").get(0);
//獲取所需數(shù)據(jù)
String title = titleElement.text();
System.out.println(title);
又或者我需要獲取頁面《手機(jī)百度》這個(gè)數(shù)據(jù):
String startPage="https://www.baidu.com";
Document document = Jsoup.connect(startPage).userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36").get();
Element elementById = document.getElementById("qrcode");
String text = elementById.getAllElements().get(0).getAllElements().get(1).getElementsByTag("b").text();
System.out.println(text);
這就是一個(gè)很簡(jiǎn)單的爬蟲編寫工具,Jsoup功能很強(qiáng)大,對(duì)直接爬取沒有動(dòng)態(tài)加載的靜態(tài)資源頁面再適合不過。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Java中SimpleDateFormat日期格式轉(zhuǎn)換詳解及代碼示例
這篇文章主要介紹了Java中SimpleDateFormat日期格式轉(zhuǎn)換詳解及代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
解決mybatisplus的分頁插件和條件構(gòu)造器自定義SQL遇到的BUG
這篇文章主要介紹了解決mybatisplus的分頁插件和條件構(gòu)造器自定義SQL遇到的BUG,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
java中的Io(input與output)操作總結(jié)(二)
這一節(jié)我們來討論關(guān)于文件自身的操作包括:創(chuàng)建文件對(duì)象、創(chuàng)建和刪除文件、文件的判斷和測(cè)試、創(chuàng)建目錄、獲取文件信息、列出文件系統(tǒng)的根目錄、列出目錄下的所有文件,等等,感興趣的朋友可以了解下2013-01-01
如何使用spring gateway微服務(wù)網(wǎng)關(guān)(基本用法)
本文介紹spring gateway的使用,包括配置文件的使用和調(diào)試跟蹤,讓大家了解spring gateway的基本用法,感興趣的朋友跟隨小編一起看看吧2024-08-08
Spark學(xué)習(xí)筆記Spark Streaming的使用
這篇文章主要介紹了Spark學(xué)習(xí)筆記Spark Streaming的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
Java實(shí)現(xiàn)的決策樹算法完整實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)的決策樹算法,簡(jiǎn)單描述了決策樹的概念、原理,并結(jié)合完整實(shí)例形式分析了java實(shí)現(xiàn)決策樹算法的相關(guān)操作技巧,代碼中備有較為詳盡的注釋便于理解,需要的朋友可以參考下2017-11-11
Java使用Junit4.jar進(jìn)行單元測(cè)試的方法
今天通過本文給大家介紹Java使用Junit4.jar進(jìn)行單元測(cè)試的方法,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-11-11

