1. 概述

Jsoup 是一个开源的HTML解析库,主要用于网页数据抓取。它提供了基于DOM API的数据解析、提取和操作功能,简单粗暴又实用。

本文将演示如何使用Jsoup解析HTML表格,包括:

  • ✅ 读取表格数据
  • ✅ 更新表格内容
  • ✅ 动态添加/删除表格行

2. 依赖配置

在项目中添加Jsoup依赖(Maven配置):

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.17.2</version>
</dependency>

最新版本可在Maven中央仓库获取。

3. 表格结构

我们使用以下HTML表格结构作为示例(完整代码见文末GitHub仓库):

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Maths</th>
            <th>English</th>
            <th>Science</th>
         </tr>
    </thead>
    <tbody>
        <tr>
            <td>Student 1</td>
            <td>90</td>
            <td>85</td>
            <td>92</td>
        </tr>
     </tbody>
</table>

⚠️ 注意:本文假设表格遵循标准结构(thead包含表头,tbody包含数据行),且不存在colspan/rowspan等复杂合并单元格。

4. 解析表格数据

4.1 基础解析逻辑

通过CSS选择器快速定位表格元素:

Element table = doc.select("table").get(0);  // 获取第一个表格
Elements rows = table.select("tr");          // 获取所有行
Elements headers = rows.get(0).select("th,td"); // 获取表头

4.2 完整解析方法

public List<Map<String, String>> parseTable(Document doc, int tableOrder) {
    Element table = doc.select("table").get(tableOrder);
    Element tbody = table.select("tbody").get(0);
    Elements dataRows = tbody.select("tr");
    Elements headerRow = table.select("tr").get(0).select("th,td");

    // 提取表头
    List<String> headers = new ArrayList<>();
    for (Element header : headerRow) {
        headers.add(header.text());
    }

    // 解析数据行
    List<Map<String, String>> parsedData = new ArrayList<>();
    for (Element row : dataRows) {
        Elements cells = row.select("th,td");
        Map<String, String> rowData = new HashMap<>();
        
        for (int i = 0; i < cells.size(); i++) {
            rowData.put(headers.get(i), cells.get(i).text());
        }
        parsedData.add(rowData);
    }
    return parsedData;
}

4.3 数据结构说明

使用List<Map<String, String>>存储解析结果:

  • ✅ 列表索引 = 行号
  • ✅ Map键 = 列名(表头)
  • ✅ Map值 = 单元格内容

4.4 单元测试验证

@Test
public void whenDocumentTableParsed_thenTableDataReturned() {
    JsoupTableParser parser = new JsoupTableParser();
    Document doc = parser.loadFromFile("Students.html");
    List<Map<String, String>> tableData = parser.parseTable(doc, 0);
    
    assertEquals("90", tableData.get(0).get("Maths")); 
}

5. 更新表格数据

5.1 单元格更新方法

// 更新文本内容
colVals.get(index).text("新值");

// 更新HTML内容(支持标签)
colVals.get(index).html("<b>新值</b>");

5.2 批量更新实现

public void updateTableData(Document doc, int tableOrder, String newValue) {
    Element table = doc.select("table").get(tableOrder);
    Elements dataRows = table.select("tbody tr");

    for (Element row : dataRows) {
        Elements cells = row.select("th,td");
        for (Element cell : cells) {
            cell.text(newValue); // 统一更新所有单元格
        }
    }
}

5.3 更新测试验证

@Test
public void whenTableUpdated_thenUpdatedDataReturned() {
    JsoupTableParser parser = new JsoupTableParser();
    Document doc = parser.loadFromFile("Students.html");
    parser.updateTableData(doc, 0, "50");
    
    List<Map<String, String>> tableData = parser.parseTable(doc, 0);
    assertEquals("50", tableData.get(2).get("Maths"));
}

6. 添加表格行

6.1 动态添加行实现

public void addRowToTable(Document doc, int tableOrder) {
    Element table = doc.select("table").get(tableOrder);
    Element tbody = table.select("tbody").get(0);
    
    // 获取列数
    int colCount = table.select("tr").get(0).select("th,td").size();
    
    // 创建新行
    Element newRow = new Element("tr");
    for (int i = 0; i < colCount; i++) {
        newRow.appendElement("td").text("11"); // 设置默认值
    }
    
    // 添加到表格
    tbody.appendChild(newRow);
}

6.2 添加行测试验证

@Test
public void whenTableRowAdded_thenRowCountIncreased() {
    JsoupTableParser parser = new JsoupTableParser();
    Document doc = parser.loadFromFile("Students.html");
    
    int initialCount = parser.parseTable(doc, 0).size();
    parser.addRowToTable(doc, 0);
    
    int newCount = parser.parseTable(doc, 0).size();
    assertEquals(initialCount + 1, newCount);
}

7. 删除表格行

7.1 删除行实现

public void deleteRowFromTable(Document doc, int tableOrder, int rowIndex) {
    Element table = doc.select("table").get(tableOrder);
    Elements rows = table.select("tbody tr");
    
    if (rowIndex < rows.size()) {
        rows.get(rowIndex).remove(); // 直接移除行元素
    }
}

7.2 删除行测试验证

@Test
public void whenTableRowDeleted_thenRowCountDecreased() {
    JsoupTableParser parser = new JsoupTableParser();
    Document doc = parser.loadFromFile("Students.html");
    
    int initialCount = parser.parseTable(doc, 0).size();
    parser.deleteRowFromTable(doc, 0, 2); // 删除第3行
    
    int newCount = parser.parseTable(doc, 0).size();
    assertEquals(initialCount - 1, newCount);
}

8. 总结

通过Jsoup可以高效实现HTML表格的完整操作:

  • 数据解析:CSS选择器+Map结构存储
  • 内容更新:支持文本/HTML两种更新方式
  • 动态修改:轻松实现行级增删操作

⚠️ 踩坑提示:处理复杂表格(合并单元格/嵌套表格)时需额外处理DOM结构,建议先用浏览器开发者工具分析目标表格结构。

完整示例代码见GitHub仓库:jsoup-table-parser-demo


原始标题:Parsing HTML Table in Java With Jsoup | Baeldung