【实战】Java使用 Jsoup 将浏览器书签 HTML 转换为 JSON(支持多级目录)

一、背景说明

浏览器(Chrome / Edge / Firefox)导出的书签文件,通常是 Netscape Bookmark HTML 格式

在实际开发中,我们可能会遇到以下需求:

  • 将浏览器书签导入到自己的系统
  • 对书签进行结构化存储(如数据库、JSON)
  • 做书签导航站、搜索、同步工具等

本文通过 Jsoup + Fastjson2 ,演示如何将书签 HTML 解析为层级 JSON 结构 ,并支持 递归子目录


二、书签 HTML 格式说明

浏览器导出的书签文件大致结构如下:

html 复制代码
<DL>
  <DT><H3>文件夹</H3>
  <DL>
    <DT><A HREF="https://www.baidu.com/">百度</A>
    <DT><H3>子文件夹</H3>
    <DL>
      <DT><A HREF="https://map.baidu.com/">百度地图</A>
    </DL>
  </DL>
</DL>

关键点:

  • <H3>:表示一个文件夹
  • <A>:表示一个书签链接
  • <DL>:表示当前文件夹的内容
  • 文件夹与其内容是 H3 → 紧跟的 DL

三、技术选型

技术 作用
Jsoup 解析 HTML DOM
Fastjson2 构建 JSON 数据
JUnit + SpringBootTest 测试运行

四、完整示例代码

下面给出 完整可运行代码,包括导入、类定义和递归方法:

java 复制代码
package com.nav.test;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class Bookmark {

    @Test
    public void main() {
        // 模拟浏览器导出的书签 HTML 内容
        String bookmarkContent = "<!DOCTYPE NETSCAPE-Bookmark-file-1>\n" +
                "<!-- This is an automatically generated file. -->\n" +
                "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n" +
                "<TITLE>Bookmarks</TITLE>\n" +
                "<H1>Bookmarks</H1>\n" +
                "<DL><p>\n" +
                "    <DT><H3 ADD_DATE=\"1632971641\" LAST_MODIFIED=\"1689686797\" PERSONAL_TOOLBAR_FOLDER=\"true\">书签栏</H3>\n" +
                "    <DL><p>\n" +
                "        <DT><A HREF=\"https://www.baidu.com/\" ADD_DATE=\"1689686710\">百度一下,你就知道</A>\n" +
                "        <DT><H3 ADD_DATE=\"1689686747\" LAST_MODIFIED=\"1689686798\">子书签</H3>\n" +
                "        <DL><p>\n" +
                "            <DT><A HREF=\"https://map.baidu.com/\" ADD_DATE=\"1689686769\">百度地图</A>\n" +
                "        </DL><p>\n" +
                "    </DL><p>\n" +
                "</DL><p>";

        // 使用 Jsoup 解析 HTML
        Document doc = Jsoup.parse(bookmarkContent);

        // 找到书签栏(Chrome 的 PERSONAL_TOOLBAR_FOLDER)
        Element mainFolder = doc.select("h3[personal_toolbar_folder]").first();

        // 递归处理
        JSONObject result = processFolder(mainFolder);

        // 输出 JSON
        System.out.println(result.toJSONString());
    }

    /**
     * 递归处理文件夹
     *
     * @param folderElement 文件夹对应的 H3 元素
     * @return JSONObject 结构 {name, links, subFolders}
     */
    private static JSONObject processFolder(Element folderElement) {
        JSONObject folderJson = new JSONObject();

        // 文件夹名称
        folderJson.put("name", folderElement.text());

        // 当前文件夹对应的 <DL>
        Element dl = folderElement.nextElementSibling();

        // 当前目录下的链接
        JSONArray links = new JSONArray();
        for (Element a : dl.select("> dt > a")) {
            JSONObject linkJson = new JSONObject();
            linkJson.put("name", a.text());
            linkJson.put("url", a.attr("href"));
            links.add(linkJson);
        }
        folderJson.put("links", links);

        // 子文件夹
        JSONArray subFolders = new JSONArray();
        for (Element h3 : dl.select("> dt > h3")) {
            subFolders.add(processFolder(h3));
        }
        folderJson.put("subFolders", subFolders);

        return folderJson;
    }
}

五、输出 JSON 示例

运行上面的代码,控制台输出类似:

json 复制代码
{
  "name": "书签栏",
  "links": [
    {
      "name": "百度一下,你就知道",
      "url": "https://www.baidu.com/"
    }
  ],
  "subFolders": [
    {
      "name": "子书签",
      "links": [
        {
          "name": "百度地图",
          "url": "https://map.baidu.com/"
        }
      ],
      "subFolders": []
    }
  ]
}

六、实现思路总结

  1. H3 表示文件夹
  2. H3 后面的 DL 是内容
  3. 使用 nextElementSibling() 关联目录
  4. 递归解析子文件夹
  5. 通过 > dt > a> dt > h3 选择器分别获取当前目录的书签和子文件夹
相关推荐
心之语歌1 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊3 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang3 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang4 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解4 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
willow8 小时前
html5基础整理
html
SimonKing8 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean9 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven9710 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55119 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java