本文目录导读:

我来为您提供几个Jsoup解析的实用案例,从基础到进阶。
基础案例:HTML解析入门
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class BasicExample {
public static void main(String[] args) {
// 1. 解析HTML字符串
String html = "<html><head><title>示例页面</title></head>"
+ "<body>"
+ "<div class='content'>"
+ " <h1>标题</h1>"
+ " <p class='text'>第一段文本</p>"
+ " <p class='text'>第二段文本</p>"
+ " <a href='https://example.com'>链接</a>"
+ "</div>"
+ "</body></html>";
Document doc = Jsoup.parse(html);
// 获取标题
String title = doc.title();
System.out.println("页面标题: " + title);
// 通过类名获取元素
Elements paragraphs = doc.getElementsByClass("text");
for (Element p : paragraphs) {
System.out.println("段落内容: " + p.text());
}
// 通过标签获取
Element heading = doc.selectFirst("h1");
System.out.println("H1内容: " + heading.text());
// 获取链接
Element link = doc.selectFirst("a");
System.out.println("链接文本: " + link.text());
System.out.println("链接地址: " + link.attr("href"));
}
}
抓取示例
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class WebScraper {
public static void main(String[] args) {
try {
// 连接并获取网页
Document doc = Jsoup.connect("https://example.com/news")
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.timeout(10000)
.get();
// 提取新闻标题和链接
Elements newsItems = doc.select("div.news-item");
System.out.println("找到 " + newsItems.size() + " 条新闻\n");
for (Element item : newsItems) {
// 获取标题
Element title = item.selectFirst("h2.title");
// 获取链接
Element link = item.selectFirst("a");
// 获取摘要
Element summary = item.selectFirst("p.summary");
if (title != null) {
System.out.println("标题: " + title.text());
}
if (link != null) {
System.out.println("URL: " + link.attr("href"));
}
if (summary != null) {
System.out.println(" " + summary.text());
}
System.out.println("---");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
表格数据提取
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TableParser {
// 定义数据模型
static class Student {
String name;
int age;
String grade;
@Override
public String toString() {
return String.format("学生{姓名='%s', 年龄=%d, 班级='%s'}",
name, age, grade);
}
}
public static void main(String[] args) {
String html = "<html><body>"
+ "<table id='student-table'>"
+ " <thead>"
+ " <tr><th>姓名</th><th>年龄</th><th>班级</th></tr>"
+ " </thead>"
+ " <tbody>"
+ " <tr><td>张三</td><td>18</td><td>高三(1)班</td></tr>"
+ " <tr><td>李四</td><td>17</td><td>高三(2)班</td></tr>"
+ " <tr><td>王五</td><td>18</td><td>高三(1)班</td></tr>"
+ " </tbody>"
+ "</table>"
+ "</body></html>";
Document doc = Jsoup.parse(html);
List<Student> students = parseTable(doc);
System.out.println("解析结果:");
students.forEach(System.out::println);
}
private static List<Student> parseTable(Document doc) {
List<Student> students = new ArrayList<>();
// 选择表格数据行(跳过表头)
Elements rows = doc.select("#student-table tbody tr");
for (Element row : rows) {
Elements cells = row.select("td");
if (cells.size() >= 3) {
Student student = new Student();
student.name = cells.get(0).text();
student.age = Integer.parseInt(cells.get(1).text());
student.grade = cells.get(2).text();
students.add(student);
}
}
return students;
}
}
复杂选择器示例
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class SelectorExamples {
public static void main(String[] args) {
String html = "<html><body>"
+ "<div id='main'>"
+ " <ul class='nav'>"
+ " <li class='active'><a href='/home'>首页</a></li>"
+ " <li><a href='/products'>产品</a></li>"
+ " <li><a href='/about'>关于我们</a></li>"
+ " </ul>"
+ " <div class='content'>"
+ " <p data-id='1'>第一个段落</p>"
+ " <p data-id='2' class='highlight'>第二个段落</p>"
+ " <p data-id='3'>第三个段落</p>"
+ " </div>"
+ "</div>"
+ "</body></html>";
Document doc = Jsoup.parse(html);
System.out.println("=== 选择器示例 ===\n");
// 1. ID选择器
Element mainDiv = doc.selectFirst("#main");
System.out.println("ID选择器 #main: " + mainDiv.tagName());
// 2. 类选择器
Elements activeItems = doc.select(".active");
System.out.println("类选择器 .active: " + activeItems.size() + " 个元素");
// 3. 属性选择器
Elements withDataId = doc.select("[data-id]");
System.out.println("属性选择器 [data-id]: " + withDataId.size() + " 个元素");
// 4. 组合选择器
Elements navLinks = doc.select("ul.nav > li > a");
System.out.println("组合选择器: " + navLinks.size() + " 个链接");
// 5. 包含文本选择
Elements paragraphWithText = doc.select("p:contains(第二个)");
System.out.println("文本选择: " + paragraphWithText.text());
// 6. 相邻兄弟选择器
Element highlight = doc.selectFirst(".highlight");
Element nextParagraph = highlight.nextElementSibling();
System.out.println("相邻兄弟: " + nextParagraph.text());
// 7. 父元素查找
Element paragraph = doc.selectFirst("p");
Element parentDiv = paragraph.parent();
System.out.println("父元素: " + parentDiv.className());
// 8. 第一个和最后一个
Element firstP = doc.selectFirst("p:first-child");
Element lastP = doc.selectFirst("p:last-child");
System.out.println("第一个p: " + firstP.text());
System.out.println("最后一个p: " + lastP.text());
}
}
处理相对URL和文件下载
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
public class ImageDownloader {
public static void main(String[] args) {
try {
// 设置baseUri用于解析相对路径
String baseUrl = "https://example.com/gallery";
Document doc = Jsoup.connect(baseUrl).get();
// 处理图片链接
Elements images = doc.select("img");
for (Element img : images) {
// 获取图片地址(相对路径转绝对路径)
String src = img.absUrl("src");
// 获取alt文本(用于文件名)
String alt = img.attr("alt");
String fileName = alt.isEmpty() ?
"image_" + System.currentTimeMillis() :
alt.replace(" ", "_");
System.out.println("图片地址: " + src);
System.out.println("文件名: " + fileName);
// 下载图片(可选)
// downloadImage(src, "downloads/" + fileName + ".jpg");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void downloadImage(String imageUrl, String savePath)
throws IOException {
// 创建目录
Files.createDirectories(Paths.get(savePath).getParent());
// 下载并保存
try (InputStream in = new URL(imageUrl).openStream()) {
Files.copy(in, Paths.get(savePath));
}
System.out.println("图片已保存: " + savePath);
}
}
处理表单数据
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.FormElement;
import org.jsoup.nodes.Element;
import java.io.IOException;
import java.util.Map;
public class FormProcessor {
public static void main(String[] args) {
try {
// 1. 提交GET请求
Document doc = Jsoup.connect("https://httpbin.org/get")
.data("username", "zhangsan")
.data("age", "25")
.get();
System.out.println("GET请求响应:");
System.out.println(doc.body().text());
// 2. 提交POST请求
Connection.Response response = Jsoup.connect("https://httpbin.org/post")
.data("username", "lisi")
.data("password", "123456")
.method(Connection.Method.POST)
.execute();
Document responseDoc = response.parse();
System.out.println("\nPOST请求响应:");
System.out.println(responseDoc.body().text());
// 3. 模拟表单提交
String html = "<form id='login-form' action='/login' method='post'>"
+ "<input type='text' name='username' value=''>"
+ "<input type='password' name='password' value=''>"
+ "<button type='submit'>登录</button>"
+ "</form>";
Document formDoc = Jsoup.parse(html);
// 获取表单
Element form = formDoc.selectFirst("#login-form");
// 模拟填写表单
form.selectFirst("input[name=username]").val("张三");
form.selectFirst("input[name=password]").val("abc123");
// 提交表单
// 实际项目中会发送到指定action地址
System.out.println("\n表单数据:");
Elements inputs = form.select("input");
for (Element input : inputs) {
System.out.println(input.attr("name") + " = " + input.val());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用Cookies保持会话
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.util.Map;
public class SessionHandler {
public static void main(String[] args) {
Connection connection = Jsoup.connect("https://example.com/login");
try {
// 1. 登录获取cookies
Connection.Response loginResponse = connection
.data("username", "admin")
.data("password", "123456")
.method(Connection.Method.POST)
.execute();
// 获取cookies
Map<String, String> cookies = loginResponse.cookies();
System.out.println("登录成功,Cookies: " + cookies);
// 2. 使用cookies访问需要认证的页面
Document protectedPage = Jsoup.connect("https://example.com/dashboard")
.cookies(cookies)
.get();
System.out.println("受保护页面标题: " + protectedPage.title());
// 3. 保持会话状态(多次请求)
Connection.Response firstRequest = Jsoup.connect("https://example.com/api/data")
.cookies(cookies)
.execute();
// 后续请求自动携带cookies
Connection.Response secondRequest = Jsoup.connect("https://example.com/api/more")
.cookies(cookies)
.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
异常处理最佳实践
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.UnsupportedMimeTypeException;
import org.jsoup.nodes.Document;
import java.io.IOException;
public class ErrorHandling {
public static void main(String[] args) {
String[] urls = {
"https://example.com",
"https://nonexistent-site.com",
"https://example.com/not-found",
"https://example.com/file.pdf" // 非HTML内容
};
for (String url : urls) {
try {
fetchUrl(url);
} catch (HttpStatusException e) {
System.out.println("HTTP状态错误: " + url);
System.out.println("状态码: " + e.getStatusCode());
} catch (UnsupportedMimeTypeException e) {
System.out.println("不支持的MIME类型: " + url);
} catch (IOException e) {
System.out.println("IO错误: " + url);
System.out.println("原因: " + e.getMessage());
} catch (Exception e) {
System.out.println("未知错误: " + url);
e.printStackTrace();
}
System.out.println("---");
}
}
private static void fetchUrl(String url) throws IOException {
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0")
.timeout(5000)
.followRedirects(true)
.ignoreHttpErrors(false)
.get();
System.out.println("成功获取: " + url);
System.out.println("标题: " + doc.title());
}
}
使用建议
-
添加依赖 (Maven):
<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.16.1</version> </dependency>
-
性能优化:
- 使用连接池复用连接
- 合理设置超时时间
- 限制并发请求数量
-
反爬虫处理:
- 设置合理的User-Agent
- 添加请求间隔
- 使用代理IP
-
数据提取规范:
- 优先使用id选择器
- 避免过度使用链式选择器
- 对optional元素进行空值检查
这些案例覆盖了Jsoup的主要功能,您可以根据实际需求进行调整和扩展,如果您有特定的使用场景,我可以提供更针对性的示例。