Jsoup 是 Java 專為真實世界 HTML 設計的解析器,支援不完整標籤修正、CSS 選擇器、DOM 操作、XSS 防護等。
// 字串解析
String html = "Test Content
";
Document doc = Jsoup.parse(html);
// URL 載入 (支援連線參數鏈)
Document doc = Jsoup.connect("https://example.com")
.userAgent("Mozilla/5.0")
.timeout(5000)
.get();
// 檔案載入 (指定編碼與 baseUri 處理相對連結)
File input = new File("/tmp/page.html");
Document doc = Jsoup.parse(input, "UTF-8", "https://example.com/");
Element content = doc.getElementById("content");
Elements links = content.getElementsByTag("a");
for (Element link : links) {
String href = link.attr("href"); // 屬性
String text = link.text(); // 文字內容
String html = link.html(); // 內部 HTML
String outer = link.outerHtml(); // 含自身標籤
}
| 方法 | 說明 |
|---|---|
| getElementById(id) | 依 ID 找單一元素 |
| getElementsByTag(tag) | 依標籤名找集合 |
| getElementsByClass(className) | 依 class 找集合 |
| getElementsByAttribute(key) | 依屬性存在性 |
| parent() / children() / child(i) | 樹向導航 |
| siblingElements() / nextElementSibling() | 同級導航 |
// 基礎
doc.select("a[href]") // 有 href 的 a
doc.select("img[src$=.png]") // src 以 .png 結尾
doc.select("div.masthead") // class=masthead 的 div
// 層級
doc.select("div.content > p") // 直接子元素 p
doc.select("body > *") // body 所有直接子元素
doc.select("h3.r > a") // h3.r 直系子 a
// 偽選擇器
doc.select("td:lt(3)") // 前 3 個 td
doc.select("div p:gt(2)") // 第 3 個以後的 p
doc.select("form input:eq(1)") // 第 2 個 input
doc.select("div:has(p)") // 含 p 的 div
doc.select("div:not(.logo)") // 排除 class=logo 的 div
doc.select("p:contains(jsoup)") // 含文字 jsoup (不分大小寫)
doc.select("div:matches(?i)login") // 文字符合正則
doc.select("div.masthead, div.logo") // 多選擇器聯集
doc.select("a[href].highlight") // 連續條件
String html = "An Example link.
";
Document doc = Jsoup.parse(html);
Element link = doc.select("a").first();
link.attr("href"); // "https://example.com/"
link.attr("href", "new"); // 修改屬性
link.text(); // "Example"
link.text("New Text"); // 修改文字
link.html(); // "Example"
link.html("New"); // 修改內部 HTML
link.outerHtml(); // "..."
package org.jsoup.examples;
import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import org.jsoup.select.Elements;
import java.io.IOException;
public class ListLinks {
public static void main(String[] args) throws IOException {
String url = args[0];
System.out.printf("Fetching %s...%n", url);
Document doc = Jsoup.connect(url).get();
Elements links = doc.select("a[href]");
Elements media = doc.select("[src]");
Elements imports = doc.select("link[href]");
System.out.printf("%nMedia: (%d)%n", media.size());
for (Element src : media) {
if (src.tagName().equals("img")) {
System.out.printf(" * %s: <%s> %sx%s (%s)%n",
src.tagName(), src.attr("abs:src"),
src.attr("width"), src.attr("height"),
trim(src.attr("alt"), 20));
} else {
System.out.printf(" * %s: <%s>%n", src.tagName(), src.attr("abs:src"));
}
}
System.out.printf("%nImports: (%d)%n", imports.size());
for (Element link : imports) {
System.out.printf(" * %s <%s> (%s)%n",
link.tagName(), link.attr("abs:href"), link.attr("rel"));
}
System.out.printf("%nLinks: (%d)%n", links.size());
for (Element link : links) {
System.out.printf(" * a: <%s> (%s)%n",
link.attr("abs:href"), trim(link.text(), 35));
}
}
private static String trim(String s, int w) {
return s.length() > w ? s.substring(0, w-1) + "." : s;
}
}
doc.baseUri() 解析相對連結為絕對 (attr("abs:href"))。Jsoup.clean(html, Whitelist.basic()) 防 XSS,保留安全標籤。doc.html() 壓縮;doc.outerHtml() 含文件宣告;OutputSettings.prettyPrint(true) 美化縮排。FormElement 自動處理表單提交、輸入欄位。<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
| 問題 | 原因 | 解決 |
|---|---|---|
| 中文亂碼 | 未指定編碼 | Jsoup.parse(input, "UTF-8") 或連線 .parser(Parser.xmlParser()) |
| 動態渲染內容抓不到 | Jsoup 不執行 JS | 改用 Selenium/Playwright/Puppeteer |
| 選擇器不匹配 | HTML 結構異於預期 | 用 browser DevTools 驗證選擇器 |
| 大檔案 OOM | DOM 全載入記憶體 | 流式處理或增加 -Xmx |