java第三方包學習之jsoup

前言

使用python寫爬蟲的人,應該都聽過beautifulsoup4這個包,用來它來解析網頁甚是方便。那麼在java裏有沒有相似的包呢?固然有啦!並且也很是好用。下面隆重介紹jsouphtml

簡介

jsoup 是一個解析 HTML 的第三方 java 庫,它提供了一套很是方便的 API,可以使用 DOM,CSS 以及類 jQuery 的操做方法來取出和操做數據。java

jsoup 實現了 WHATWG HTML5 規範,可以與現代瀏覽器解析成相同的DOM。其解析器可以盡最大可能從你提供的HTML文檔來建立一個乾淨的解析結果,不管HTML的格式是否完整。好比它能夠處理沒有關閉的標籤。python

舉個栗子:正則表達式

<p>Lorem <p>Ipsum parses to <p>Lorem</p> <p>Ipsum</p>

它也能夠處理隱式標籤,建立可靠的文檔結構(html標籤包含head 和 body,在head只出現恰當的元素)。api

下載

官網地址在這裏, 對應的中文文檔在這裏,以及 jar 包的下載地址瀏覽器

一個文檔的對象模型

  • 文檔由多個ElementsTextNodes組成 ;cookie

  • 其繼承結構以下:Document繼承Element繼承Node, TextNode繼承 Node.post

  • 一個Element包含一個子節點集合,並擁有一個父Element。他們還提供了一個惟一的子元素過濾列表。編碼

獲取 Document 對象

jsoup 能夠從包括字符串、URL 地址以及本地文件來加載 HTML 文檔,並生成 Document 對象實例。url

// (1)從字符串中獲取
String html = "<html><head><title>First parse</title></head>"
  + "<body><p>Parsed HTML into a doc.</p></body></html>";
Document doc1 = Jsoup.parse(html);

// (2)從 URL 直接加載 HTML 文檔
// get方法
Document doc2 = Jsoup.connect("http://www.163.com").get(); 
// post方法
Document doc = Jsoup.connect("http://example.com")
  .data("query", "Java")
  .userAgent("Mozilla")
  .cookie("auth", "token")
  .timeout(3000)
  .post();
 
  // (3)從文件中加載 HTML 文檔
File input = new File("D:/test.html"); 
Document doc = Jsoup.parse(input,"UTF-8","http://www.163.com/");

經常使用到的方法以下:

public static Connection connect(String url)
public static Document parse(String html, String baseUri)
public static Document parse(URL url,  int timeoutMillis) throws IOException
public static Document parse(File in,  String charsetName) throws IOException
public static Document parse(InputStream in, String charsetName,  String baseUrl)  throws IOException

parse方法可以將輸入的 HTML 解析爲一個新的文檔 (Document),只要解析的不是空字符串,就能返回一個結構合理的文檔,其中包含(至少) 一個head和一個body元素。
上面的參數 baseUri的做用是,若是要解析的html中存在相對路徑,那麼就根據這個參數變成絕對路徑, 若是不須要能夠傳入一個空字符串。

注:經過connect方法來得到 html 源碼,有的時候會遇到亂碼的問題,這個時候該怎麼辦麼?方法裏有一個 parse 方法,傳入參數 InputStreamcharsetName以及baseUrl,全部能夠這樣解決:

String url = "http://xxxxxxx";
Document document = Jsoup.parse(new URL(url).openStream(), "GBK", url);// 以 gbk 編碼爲慄。

Jsoup的強項是解析html,固然了,它能處理一些簡單狀況,遇到複雜的情形仍是使用 httpClient 這個包吧,你值得擁有!

解析並提取 HTML 元素

使用傳統的操做DOM的方式

舉個栗子

Element content = doc.getElementById("content");
Elements links = content.getElementsByTag("a");
Elements mx = content.getElementsByClass("help");

:doc 爲 Document 對象。
還有寫經常使用的方法,好比

public Elements getElementsByAttributeValue(String key,  String value)
public Element attr(String attributeKey,  String attributeValue)
public Elements getAllElements()
// 得到孩子節點中全部的文本拼接
public String text()
// 得到節點的內部html
public String html()

Document 對象還有一個方法

// 獲取標題
public String title()
// 得到某節點的html,這個方法繼承自Node類,因此Element類也有該方法
public String outerHtml()

選擇器

在元素檢索方面,jsoup 的選擇器簡直無所不能。
jsoup 選擇器不少,這裏僅僅舉出幾個栗子,

Elements links = doc.select("a[href]"); // 具備href屬性的a標籤
Elements pngs = doc.select("img[src$=.png]");// src屬性以.png結尾的img標籤
Element masthead = doc.select("div.masthead").first();// class屬性爲masthead的div標籤中的第一個
Elements resultLinks = doc.select("h3.r > a"); // class屬性爲r的h3標籤的直接子a標籤
Elements resultLinks = doc.select(img[src~=(?i)\.(png|jpe?g)])

Selector選擇器概述

tagname: 經過標籤查找元素,好比:a
ns|tag: 經過標籤在命名空間查找元素,好比:能夠用 fb|name 語法來查找 <fb:name> 元素
#id: 經過ID查找元素,好比:#logo
.class: 經過class名稱查找元素,好比:.masthead
[attribute]: 利用屬性查找元素,好比:[href]
[^attr]: 利用屬性名前綴來查找元素,好比:能夠用[^data-] 來查找帶有HTML5 Dataset屬性的元素
[attr=value]: 利用屬性值來查找元素,好比:[width=500]
[attr^=value], [attr$=value], [attr*=value]: 利用匹配屬性值開頭、結尾或包含屬性值來查找元素,好比:[href*=/path/]
[attr~=regex]: 利用屬性值匹配正則表達式來查找元素,好比: img[src~=(?i)\.(png|jpe?g)]
*: 這個符號將匹配全部元素

Selector選擇器組合使用

el#id: 元素+ID,好比: div#logo
el.class: 元素+class,好比: div.masthead
el[attr]: 元素+class,好比: a[href]
任意組合,好比:a[href].highlight
ancestor child: 查找某個元素下子元素,好比:能夠用.body p 查找在"body"元素下的全部 p元素
parent > child: 查找某個父元素下的直接子元素,好比:能夠用div.content > p 查找 p 元素,也能夠用body > * 查找body標籤下全部直接子元素
siblingA + siblingB: 查找在A元素以前第一個同級元素B,好比:div.head + div
siblingA ~ siblingX: 查找A元素以前的同級X元素,好比:h1 ~ p
el, el, el:多個選擇器組合,查找匹配任一選擇器的惟一元素,例如:div.masthead, div.logo

僞選擇器selectors

:lt(n): 查找哪些元素的同級索引值(它的位置在DOM樹中是相對於它的父節點)小於n,好比:td:lt(3) 表示小於三列的元素
:gt(n):查找哪些元素的同級索引值大於n,好比: div p:gt(2)表示哪些div中有包含2個以上的p元素
:eq(n): 查找哪些元素的同級索引值與n相等,好比:form input:eq(1)表示包含一個input標籤的Form元素
:has(seletor): 查找匹配選擇器包含元素的元素,好比:div:has(p)表示哪些div包含了p元素
:not(selector): 查找與選擇器不匹配的元素,好比: div:not(.logo) 表示不包含 class=logo 元素的全部 div 列表
:contains(text): 查找包含給定文本的元素,搜索不區分大不寫,好比: p:contains(jsoup)
:containsOwn(text): 查找直接包含給定文本的元素
:matches(regex): 查找哪些元素的文本匹配指定的正則表達式,好比:div:matches((?i)login)
:matchesOwn(regex): 查找自身包含文本匹配指定正則表達式的元素

注: 上述僞選擇器索引是從0開始的,也就是說第一個元素索引值爲0,第二個元素index爲1等。
對於 Elements 的來歷,看這裏

public class Elements extends ArrayList<Element>

另外,能夠查看Selector API參考來了解更詳細的內容
能夠看出,jsoup 使用跟 jQuery 如出一轍的選擇器對元素進行檢索,以上的檢索方法若是換成是其餘的 HTML 解釋器,至少都須要不少行代碼,而 jsoup 只須要一行代碼便可完成。

修改獲取數據

// 爲全部連接增長 rel=nofollow 屬性
doc.select("div.comments a").attr("rel", "nofollow"); 
 // 爲全部連接增長 class=mylinkclass 屬性
doc.select("div.comments a").addClass("mylinkclass"); 
// 刪除全部圖片的 onclick 屬性
doc.select("img").removeAttr("onclick"); 
// 清空全部文本輸入框中的文本
doc.select("input[type=text]").val(""); 
// 得到rel屬性的值
doc.select("div.comments a").attr("rel");

參考

  1. 使用 jsoup 對 HTML 文檔進行解析和操做

  2. jsoup 1.9.2 API

相關文章
相關標籤/搜索