返回作品列表

网友作品 #000199 · 提交于 2026/08/26

语雀导出转Markdown工具:lakebook批量无损转换

★★★★★程序员水平AI 编程工具国内顶级模型python

作品作者

李伟坚-Excel催化剂&EasyShu作者程序员水平微信号liweijian08可加好友交流
开发工具
AI 编程工具
AI 模型
国内顶级模型
使用 Skill
python
提交你的作品

作品简介

语雀知识库导出后得到的是私有格式(lakebook 压缩包 + Lake 格式 JSON),不能直接当 Markdown 用。本工具把这些原始导出文件完整、批量地转换成标准 Markdown:直接解析源头数据 body_asl 字段,而不是先渲染成 HTML 再转换——后者会因中途报错静默漏掉大量文档。实测 3 个真实知识库共 375 篇文档全部转换成功、0 篇失败,无 Lake 标记残留。

核心亮点

  • 不丢内容:自研 Lake 解析器逐元素、逐 card 类型精确映射 Markdown,覆盖标题、引用与 alert 提示块、多级列表、任务清单、代码块、GFM 表格(含合并单元格降级)、视频/附件卡片、语雀文档内链等
  • 不丢结构:按语雀知识库目录树(TOC)还原文件夹层级,生成带可点击链接的 README 目录索引;目录树外的孤儿文档归入「未分类」
  • 资源本地化:图片附件并发下载到本地 assets 文件夹,链接自动改写相对路径,离线可看;单个资源失败自动保留远程链接,不影响整体转换
  • 源形态兼容:支持已解压文件夹、多知识库父目录、lakebook/zip/tar 压缩包三种源(自动探测 tar 格式,含 zip-slip 路径穿越防护与中文文件名编码修复)
  • 过程可控:后台线程转换不卡界面,分阶段进度汇报(转换文档 x/y、下载资源 x/y),支持随时取消;所有失败弹窗提示 + 写日志,绝不静默
  • 开箱即用:单文件 exe(约 44MB)无需 Python 环境;输出文件名自动安全化(非法字符替换、保留名规避、超长截断、同名加序号),不区分大小写登记已占用路径,彻底避免覆盖
  • 质量保障:26 个单元测试 + ruff/mypy 零告警 + 真实数据端到端验证 + 打包后冒烟测试

技术与工具

  • Python 3.12(uv 管理环境);界面用 NiceGUI(Native 模式),文件对话框改用 tkinter 进程内直调 Windows 原生窗体
  • BeautifulSoup4 + html5lib 解析、PyYAML 解析目录树、httpx + 线程池并发下载资源、PyInstaller 打包 onefile exe
  • pytest + ruff + mypy 质量流水线;开发使用 AI 编程工具搭配国内顶级模型

开发过程

  • 关键决策一:解析 body_asl 而非 body_html——前者是 Lake 源头数据,之前用 HTML 工具转换「漏很多内容」的根因就在渲染产物丢元素
  • 关键决策二:lakebook 后缀有欺骗性,实为 tar 格式,实现上先按 zip 解、失败再按 tar 解,同一段代码天然支持普通 zip/tar 源
  • 关键决策三:NiceGUI 原生文件对话框在 onefile 打包后走跨进程消息队列不稳定,改用 tkinter 直调 Win32 原生窗体,打包后 100% 可用
  • 作者的感受:尝试新 UI(NiceGUI)会翻车,不如最朴素的 GUI 稳,「要好看就要多花时间与 token」

适用场景

  • 语雀官方不给 Markdown 格式导出,需要把知识库迁移到其他 Markdown 平台的用户
  • 希望离线查看、本地归档语雀导出文档的使用者
原始提交内容(点开查看,可复制全文去问 AI)

语雀转 Markdown(YuqueToMarkdown)使用与技术指南

把语雀导出的 lakebook / JSON 文档完整转换为 Markdown 的 Windows 桌面工具 版本:1.0 | 打包形态:单文件 exe(约 44 MB,无需安装 Python)


一、工具简介

语雀知识库导出后得到的是私有格式(lakebook 压缩包 + Lake 格式 JSON),不能直接当 Markdown 用。本工具把这些原始导出文件完整、批量转换成标准 Markdown,解决的核心痛点:

  • 不丢内容:直接解析语雀原始 Lake 格式(body_asl 字段),而不是先渲染成 HTML 再转换——后者会因中途报错静默漏掉大量文档
  • 不丢结构:按语雀知识库的目录树(TOC)还原文件夹层级,并生成 README 目录索引
  • 资源本地化:可一键把图片、附件下载到本地 assets 文件夹,链接自动改写为相对路径
  • 双击就能用:打包成单文件 exe,拿到任何 Windows 电脑都能直接运行,不依赖 Python 环境

实测数据:3 个真实知识库共 375 篇文档全部转换成功,0 篇失败,无 Lake 标记残留。


二、快速上手(三步走)

第 1 步:选择源

界面上有两种选法,可以混用:

按钮 作用
选文件夹… 选择已解压的知识库文件夹(也可以选包含多个知识库的父目录)
选压缩包… 直接选择 .lakebook / .zip / .tar 压缩包(可按住 Ctrl 多选)

选好的路径会出现在输入框里,多个源用分号 ; 分隔。也可以直接手动粘贴路径进来。

输入框下方会实时提示识别结果,例如:发现 3 个知识库;2 个压缩包(转换时自动解压)。

源的三种典型形态都支持:

  1. 单个知识库文件夹(里面有 $meta.json + 一堆文档 JSON)
  2. 包含多个知识库的父目录(每个子文件夹是一个知识库)
  3. 语雀官方导出的 lakebook 压缩包(tar 格式,无需先解压)

第 2 步:选择输出文件夹

点「浏览…」选一个保存结果的位置。每个知识库会在输出目录下生成独立的子文件夹。

第 3 步:开始转换

点「开始转换」,进度条和状态栏实时更新,运行日志区显示关键节点。转换完成后:

  • 点「打开输出文件夹」直接查看结果
  • 出问题时点左侧「打开日志目录」查看详细日志(按日期分文件)

三、功能详解

3.1 输出目录结构

以转换 EasyShu图表插件.lakebook 为例:

输出目录/
 EasyShu图表插件/           lakebook 内部的 hash 目录名会自动改回压缩包名
     README.md              目录索引(按 TOC 层级生成,含可点击链接)
     欢迎语.md
     快速上手/
        安装指南.md
        常见问题.md
     assets/                图片附件(开启下载时生成)
         xxx.png

要点:

  • 文档夹层级完全按语雀目录树还原;不在目录树里的“孤儿文档”归入 未分类/
  • 文件名经过 Windows 安全化处理:非法字符替换、保留名(CON/NUL 等)规避、超长截断、同名自动加序号 名称 (2).md
  • lakebook 解压出来的顶层目录是一串 hash(如 0a223e3b…),工具会自动改用压缩包文件名作为输出文件夹名

3.2 资源下载开关

状态 行为
开启(默认) 文档中的图片、附件下载到 assets/,Markdown 里链接改为本地相对路径,离线可看
关闭 不下载,保留语雀远程链接(需要网络且资源未失效时才能查看)

下载是并发执行的(多线程),单个资源失败不影响整体——失败项自动保留远程链接,转换结束后日志会汇总 成功数/总数。

3.3 Lake 格式转换覆盖范围

类别 支持的内容
基础块 标题 h1–h6、段落、引用块(含 NOTE/TIP/WARNING 等 alert 标记)、水平线
列表 有序 / 无序列表,支持多级嵌套、任务清单
代码 代码块(保留语言标记)、行内代码
富文本 粗体、斜体、删除线、链接、转义字符
媒体 图片、视频卡片(转链接)、附件卡片(转下载链接,含文件大小)
表格 GFM 表格(含表头、对齐、合并单元格降级处理)
其他 标签(label)、语雀文档内链、第三方嵌入卡片(转链接或占位说明)、alert 提示块

3.4 转换过程可观测、可取消

  • 后台线程执行转换,界面不卡死
  • 进度分阶段汇报:转换文档 12/310 下载资源 45/120
  • 「取消」按钮可随时中止(已完成写入的文档保留)
  • 所有按钮操作失败都会弹窗提示 + 写日志,绝不静默

四、技术架构

4.1 技术栈

层次 选型
界面 NiceGUI(Native 模式,pywebview 双进程窗口)
文件对话框 tkinter(Windows 原生对话框,进程内直调)
HTML/Lake 解析 BeautifulSoup4 + html5lib
目录树 PyYAML(解析 $meta.json 内嵌的 tocYml)
资源下载 httpx + ThreadPoolExecutor 并发
打包 PyInstaller(onefile + windowed,内置 PNG 图标)
质量保障 pytest(26 个用例)+ ruff + mypy
环境管理 uv(Python 3.12)

4.2 模块分层

src/yuque2md/
 lake_parser.py   # Lake 格式  Markdown 的解析器(纯函数,无 IO)
 toc.py           # $meta.json  目录树(TocNode)
 downloader.py    # 资源并发下载 + 文件名安全化
 core.py          # 转换编排:扫描/解压/规划路径/调用解析器/生成索引
 ui.py            # NiceGUI 界面 + 事件循环 + 后台线程通信
 main.py          # 入口:日志、端口、native 窗口启动
 logging_setup.py # 按日期分文件、单文件 5MB、保留 30 天
 resources.py     # 打包后的资源路径处理

核心调用链:

UI 线程  convert_sources(源列表)
               目录源  scan_books()
               压缩包源  extract_archive()(ziptar 自动探测)
               逐知识库 convert_book()
                     load_toc()           目录树
                     convert_lake_to_markdown()   单篇解析
                     AssetDownloader      资源下载(可选)
                     README 索引生成

UI 与后台线程之间用 queue.Queue 传事件(progress / done / error),界面定时器轮询刷新,避免跨线程直接操作 UI。

4.3 关键设计决策

** 为什么解析 body_asl 而不是 body_html**

语雀导出的每个文档 JSON 里同时有 body_html 和 body_asl 两个字段。body_asl 是 Lake 格式(HTML 变体 + <card> 扩展元素),是源头数据;body_html 是渲染产物,某些元素会丢失或转义异常。之前用 HTML 工具转换“漏很多内容”,根因就在这里。本工具直接实现 Lake 解析器,逐元素、逐 card 类型精确映射到 Markdown。

** lakebook 格式探测**

.lakebook 后缀具有欺骗性——它是 tar 格式(魔数验证),不是 zip。实现上先按 zip 解,抛 BadZipFile 再降级按 tar 解,两者都失败才报错。同一段代码因此也天然支持普通 .zip 和 .tar 源。解压统一在临时目录进行,带 zip-slip 路径穿越防护和中文文件名编码修复(cp437UTF-8/GBK)。

** 文件对话框为什么用 tkinter 而不是 pywebview**

NiceGUI Native 官方推荐 app.native.main_window.create_file_dialog(),但它走跨进程消息队列(主进程发请求 webview 子进程弹窗 队列回传),在 onefile 打包后的 exe 里该链路不稳定,可能永远等不到回包——表现为点击按钮无任何反应。tkinter 对话框在进程内直接调用 Win32 原生窗体(用户看到的就是 Windows 自带的文件/文件夹选择窗体),打包后 100% 可用,是桌面程序的标准做法。详见《踩坑总结-NiceGUI原生对话框与lakebook解析.md》。

** 输出路径规划**

  • 目录源本身是知识库 直接输出到输出根目录;是父目录 每个知识库一个子文件夹
  • 压缩包源 一律输出到 输出目录/压缩包名/
  • _UsedPaths 集合登记所有已占用路径(不区分大小写),彻底避免同名覆盖

4.4 质量保障

  • 26 个单元测试:Lake 解析器各元素覆盖、TOC 构建、目录规划、lakebook(tar)/zip/混合源转换、文件名安全化、多路径输入解析
  • ruff + mypy 零告警:全量类型注解,from __future__ import annotations 风格
  • 真实数据端到端验证:3 个知识库 375 篇全部成功后才打包发布
  • 打包后冒烟测试:验证 exe 三进程架构(引导进程 服务进程 webview 窗口进程)正常启动

4.5 运行日志

日志位于 exe 同目录的 logs/ 下,按日期命名(app-2026-08-26.log),单文件超 5MB 自动分卷,保留 30 天。格式含 pid/tid/模块名,方便定位多线程问题。


五、开发与打包

# 开发环境(项目根目录执行)
uv sync                      # 还原依赖
uv run pytest -q             # 跑测试(26 个用例)
uv run ruff check src tests  # lint
uv run mypy src              # 类型检查
uv run yuque2md              # 开发模式运行(带控制台)

# 打包 onefile exe
.\scripts\build_windows.ps1 -BuildMode onefile
# 产物:dist\YuqueToMarkdown.exe(约 44 MB)

修改代码后建议流程:改 src/ pytest 验证 打包 冒烟测试(启动 exe 确认窗口出现) 交付。


六、常见问题

Q:启动 exe 后要等几秒才出窗口? onefile 模式每次启动要先把内嵌资源解压到临时目录,属正常现象。

Q:某些图片下载失败? 语雀部分附件链接需要登录才能访问。失败项自动保留远程链接,不影响文档本身转换,日志汇总里能看到成功/总数。

Q:转换结果里个别文档只有标题? 源文档本身内容为空(如仅建了标题的占位文档),转换行为正确。可打开源 JSON 核实 body_asl 长度为 0。

Q:能选 .7z 压缩包吗? 不能,Python 标准库只支持 zip/tar。7z 专有格式请先用 7-Zip 解压成文件夹再选文件夹。