使用 jsoup 解析網頁 HTML

栏目: Html · 发布时间: 5年前

内容简介:早些年我寫過兩篇文章,一篇是關於jsoup 可以做到:
使用 jsoup 解析網頁 HTML

HTML 5

如果你需要解析網頁內容,可以使用 jsoup 這個 Java 函式庫來幫助你解析網頁 HTML。

什麼是 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 檔案加入你的專案中,但更好的作法是使用 MavenGradle 的自動化工具。

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 解析函式庫來處理,就能取得內容了。

參考資料


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Software Engineering for Internet Applications

Software Engineering for Internet Applications

Eve Andersson、Philip Greenspun、Andrew Grumet / The MIT Press / 2006-03-06 / USD 35.00

After completing this self-contained course on server-based Internet applications software, students who start with only the knowledge of how to write and debug a computer program will have learned ho......一起来看看 《Software Engineering for Internet Applications》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具