内容简介:早些年我寫過兩篇文章,一篇是關於jsoup 可以做到:
HTML 5
什麼是 jsoup
早些年我寫過兩篇文章,一篇是關於 如何使用 GET/PSOT 方法來取得網頁資料 ,另一篇則是如何解析網頁,這兩篇所提到的作法都偏低階,使用上不是那麼有效率,jsoup 可以讓你更快、更容易的做到下載及解析網頁的任務。
jsoup 是一個 Java library ,它提供了方便易用的 API 來解析 HTML,使用的方法和 CSS 的選擇器或 jquery 有點像。
jsoup 可以做到:
- 從網路連結 (URL)、檔案及字串中解析 HTML
- 使用 DOM 樹遍歷或 CSS 的選擇器來尋找資料
- 操縱 HTML 元素、屬性和文字
- 避免 XSS 攻擊
- 輸出簡潔的 HTML
如何使用 jsoup
1. 安裝
目前為 1.11.3 版,你可以直接下載 jsoup-1.11.3.jar 檔案加入你的專案中,但更好的作法是使用 Maven 或 Gradle 的自動化工具。
Maven
<dependency> <!-- jsoup HTML parser library @ https://jsoup.org/ --> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.3</version> </dependency>
Gradle
// jsoup HTML parser library @ https://jsoup.org/ compile 'org.jsoup:jsoup:1.11.3'
2. 解析完整 HTML 字串
先從最簡單的字串開始,假設你有一段 HTML 字串,如何解析它呢?請看以下範例:
註:本篇程式碼使用 Kotlin。
Kotlinimport org.jsoup.Jsoup
fun parseString() {
val html = """
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JSOUP Demo</title>
</head>
<body>
<p>This is jsoup demo by blog.tonycube.com</p>
</body>
</html>
""".trimIndent()
val doc = Jsoup.parse(html)
val tagP = doc.select("p").firstOrNull()
println(tagP?.text() ?: "") // 結果: This is jsoup demo by blog.tonycube.com
}
Jsoup.parse(String html) 方法讓你傳入一個 HTML 字串,它會解析該字串然後回傳 Document 物件,你就可以使用該物件來取得你想要的節點元素。
select(String cssQuery) 方法讓你以 CSS 選擇器 的方式指定要選取的 HTML 元素,這裡我們要找 <p></p>
,該方法會回傳 Elements 物件,這個物件是 ArrayList<Element>
的子類別,也就是說它是集合物件,可能有零個到多個結果,但是我們只要第一個,於是用 firstOrNull()
來取得第一個元素否則就是 Null
。
如果你使用 Java ,你得判斷 tagP
是否為 Null
,才能做接下來的事,Kotlin 則使用 ?
來解決這個問題,只要它不是 Null
,就使用 text()
方法取出該元素的文字。
你只要專注在 select()
這個方法,使用對的選擇器去找出你要的元素即可,剩下的就只是取資料而已。
3. 解析部份 HTML 字串
有時候你取得的字串並不是完整的 HTML 內容,而是部份元素組成,例如使用者手動輸入的內容
<div><b>Hello~~</b>I am Tony.
這時候你可以這麼用
Kotlinfun parseBodyFragment() {
val html = """<div><b>Hello~~</b>I am Tony."""
val doc = Jsoup.parseBodyFragment(html)
val body = doc.body()
println(body)
}
結果:
<body> <div> <b>Hello~~</b>I am Tony. </div> </body>
Jsoup.parseBodyFragment(String bodyHtml) 方法會將你傳入的字串插入它新增的 <body></body>
元素中。而且它可以避免錯誤的元素結構,你有沒有發現例子中少了結尾的 </div>
,但輸出的結果卻是自動補上了。如果你單純使用 parse()
方法,它只會原封不動的輸出。
Document.body() 方法只會取出 <body></body>
元素中的內容。
重要!如果你要接受使用者傳入的 HTML 字串,請使用 clean(String bodyHtml, Whitelist whitelist) 來清除不必要的內容,避免被 跨網站指令碼攻擊 (Cross-site scripting, XSS) 。
4. 解析由網址取得的 HTML
現在你可以從網路上下載某個網頁的 HTML,藉由解析該網頁來取得你想要的資料。
Kotlin// 這個範例會取得我的部落格首頁的文章標題清單
fun parseHtmlFromUrl() {
val doc = Jsoup.connect("https://blog.tonycube.com/").get()
val tagTitleList = doc.select("h1.blog-post-title")
if (tagTitleList.isEmpty()) {
println("找不到文章標題")
} else {
tagTitleList.map { it.text() }.forEach(::println)
}
}
使用 connect(String url) 方法建立一個 Connection ,然後使用 get() 方法去取得網頁的 HTML。如果發生錯誤會丟出 IOException ,你可以自行決定是否補捉並處理。
Connection 是一個介面,可以讓你串接多個實作該介面的方法,例如當你想使用 post() 方法時,可以這麼用:
Kotlinval doc = Jsoup.connect("https://abc.demo.test")
.data("query", "Kotlin")
.userAgent("Mozilla")
.timeout(10000)
.post()
data() 方法可以讓你建立 post
方法所需的資料,其他可用的方法可以在 HttpConnection 查到。
5. 解析由檔案取得的 HTML
除了從網路上下載網頁,你也可以解析本地端的 HTML 檔案。
Kotlinfun parseHtmlFromFile() {
val file = File("./test.html")
val doc = Jsoup.parse(file, "UTF-8")
// ...略
}
parse(File in, String charsetName) 方法允許你傳入一個檔案,然後它會回傳解析後的文件。
6. 如何提取資料
6.1 使用 DOM
假設你有一個 HTML 檔案如下:
HTML<!DOCTYPE html>
<html lang="zh-tw">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<div id="content">
<h1>Menu</h1>
<ul>
<li><a href="a.html">AAA</a></li>
<li><a href="b.html">BBB</a></li>
<li><a href="c.html">CCC</a></li>
<li><a href="d.html">DDD</a></li>
</ul>
<a href="e.html">EEE</a>
</div>
</body>
</html>
取得連結的方法如下:
Kotlinfun parseHtmlFromFileByDOM() {
val file = File("./test.html")
val doc = Jsoup.parse(file, "UTF-8")
val tagContent = doc.getElementById("content")
val links = doc.getElementsByTag("a")
links.forEach {
val href = it.attr("href")
val text = it.text()
println("$text - $href")
}
}
結果:
AAA - a.html BBB - b.html CCC - c.html DDD - d.html EEE - e.html
你可以在 Element 類別 的說明文件中查找 getElementXXX
相關的方法,jsoup 可以讓你非常靈活的在各個節點中移動。當你找到想要的節點後,接下來就是取得資料了,如果需要節點的屬性,可以用 attr(String attributeKey) ,如果要取得內容文字則使用 text() 或 html() 方法。
6.2 使用 CSS Selector
這個方法比較簡單好用,但是首先你得先瞭解 CSS 選擇器如何使用,示範如下:
Kotlinfun parseHtmlFromFileBySelector() {
val file = File("./test.html")
val doc = Jsoup.parse(file, "UTF-8")
val tagContent = doc.select("#content").first()
val links = tagContent.select("li > a")
links.forEach {
val href = it.attr("href")
val text = it.text()
println("$text - $href")
}
}
結果:
AAA - a.html BBB - b.html CCC - c.html DDD - d.html
select("li > a")
表示只取 <li></li>
之下的 <a></a>
節點,所以 EEE
被忽略。 #
表示取 id
屬性, .
表示取 class
屬性,其他選擇器的用法請自行瞭解,如果不熟,只要先知道幾個常用的功能即可。
7. 如何下載 JSON 內容
雖然 jsoup 不能解析 JSON 內容,但是你可以利用它來下載 JSON 格式的內容。
Kotlinfun fetchJson() {
val json = Jsoup.connect("https://jsonplaceholder.typicode.com/todos/1")
.ignoreContentType(true)
.execute()
.body()
println(json)
}
ignoreContentType(true) 用來取消內容格式的檢查,因為 JSON 的內容不是 HTML,所以如果沒有將這個方法設為 true
,就會出現資料型態的例外錯誤;因為使用 get() 會回傳含有 HTML 的內容,這樣不符合 JSON 格式,所以改用 execute() 方法,並且直接使用 body() 方法來取得字串內容。
最後將 JSON 格式的字串,使用其他 JSON 解析函式庫來處理,就能取得內容了。
參考資料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Delivering Happiness
Tony Hsieh / Grand Central Publishing / 2010-6-7 / USD 27.00
http://www.deliveringhappinessbook.com/ The visionary CEO of Zappos explains how an emphasis on corporate culture can lead to unprecedented success. Pay new employees $2000 to quit. Make custome......一起来看看 《Delivering Happiness》 这本书的介绍吧!