自打主力机换成Deepin之后,我就一直把各种在线工具往本地迁移。百度脑图这东西用了好几年,积累了大量项目拆解、读书笔记和会议纪要,但网页版打开慢、离线看不了,数据也总感觉不踏实。换到思源笔记后,我第一个想解决的就是把百度脑图里的内容完整搬过来。网上关于这个方向的教程并不多,尤其针对Deepin/UOS这种Linux桌面系统的方案更是少,我折腾了几个晚上,试了各种野路子,最后沉淀下来两条真正靠谱的路径。这篇文章就把这两条路完整拆开讲,从原理到操作到坑,一次性说清楚。
不管你是刚从Win/Mac切换到Deepin或UOS的新用户,还是早就在国产系统上办公的老手,只要你手里有百度脑图的历史数据想迁移到思源笔记,这篇文章都适用。我不绕弯子,直接讲能落地的操作。
1. 迁移前必看:数据格式分析与路线选型
1.1 百度脑图的导出格式到底是什么
百度脑图本质上是一个在线编辑的思维导图工具,它主推的导出格式是.km,但这个.km不是加密格式,也不是什么私有二进制,它其实就是基于 FreeMind 的 XML 结构做了一点调整、但外层套了一层 JSON 壳的混合体。在动手迁移之前,你先得把文件格式搞清楚,不然后面全是瞎猜。
我从百度脑图网页端导出了一份测试文件,用文本编辑器打开后发现,.km文件实际上是一个 JSON 字符串,核心内容存放在content字段里,而且这个字段的值又是一段 XML,节点层级用<node>标签嵌套表示。简单来说,文件里既有结构化数据,又有富文本描述,还有一部分样式标记在里面。
我建议你在开始迁移前先做这一步:把.km文件复制一份,用 Deepin/UOS 自带的文本编辑器(比如gedit、kate或VS Code)打开,确认一下文件内的 JSON 结构。你不需要完全看懂每一个字段,但至少要知道根节点在哪、子节点是怎么嵌套的,这对后边两种方法的选择会有直接影响。
另外,百度脑图还支持导出.mm(FreeMind 标准格式)、.xmind、.txt等格式,但实际测试下来,网页端导出的.mm在思源笔记里导入时经常丢样式,甚至出现乱码。虽然思源笔记官方文档里写着支持 FreeMind 格式,但实际导入效果并不理想。相比之下,直接处理.km文件反而更可控,这也是我把两种方法都聚焦在.km源文件上的原因。
1.2 思源笔记的导入机制与数据底座
思源笔记是本地优先的 Markdown 笔记软件,数据默认存放在工作空间目录下,以.sy格式的 JSON 文件存储,同时支持标准 Markdown 的导入导出。思源的导入机制有一个特点:它识别的不是某种专门的思维导图格式,而是 Markdown 的大纲结构。
具体来说,思源会把 Markdown 中的#、##、###标题层级自动识别为文档大纲级别,也会把-无序列表识别为节点。这给我们迁移百度脑图提供了一个清晰的思路:只要能把.km里的节点层级转换成 Markdown 的层级结构,思源就能认。
我实际测试下来,思源对 Markdown 的标题层级解析非常稳定,多级缩进的列表也能识别,但从长期维护的角度看,转成标题层级比转成列表缩进更利于后续编辑和检索。所以后边两条路线的核心逻辑,都是把.km节点压平成 Markdown 文本,差别只在于实现路径不同。
1.3 两种方案的技术路线对比
考虑到不同用户的操作习惯和技术基础不同,我整理了两条路线,分别适合不同人群:
| 方案 | 核心思路 | 操作复杂度 | 依赖工具 | 适合人群 |
|---|---|---|---|---|
| 方法一:通过 FreeMind 格式中转导入 | .km→.mm→ 思源导入 | 中等 | Python脚本或在线转换工具 | 动手能力强、喜欢批量处理的用户 |
| 方法二:通过 Markdown 大纲手动整理 | .km→ Markdown → 思源粘贴/导入 | 较低 | 文本编辑器或Python脚本 | 笔记量不大、喜欢精细整理的用户 |
我个人的建议是:如果你百度脑图里的节点数量超过 50 个,或者有大量图片链接和备注信息,直接用方法一;如果你的导图比较简单,主要是层级和文字,用方法二更省事,而且导入后基本不需要二次清洗。
2. 方法一:通过 FreeMind 标准格式中转导入
2.1 思路原理:为什么要用 FreeMind 格式中转
思源笔记虽然不直接支持百度脑图的.km,但它对 FreeMind.mm格式的导入支持是写在官方文档里的。.mm格式本身是 XML,结构清晰,节点层级通过<node TEXT="...">属性表达,非常适合程序自动化生成。
.km文件的 JSON 外壳虽然看起来复杂,但剥开之后,它的核心节点层级和.mm是高度相似的。因此,我们只需要写一个简单的转换脚本,把.km文件中的节点结构提取出来,重新包装成.mm格式,再让思源导入,就能完整保留层级关系。
这条路的优势在于:思源导入.mm时会自动创建子文档或整篇文档,不需要你手动复制粘贴,适合批量处理几十个文件。缺点是.mm里带的一些复杂样式(超链接颜色、图标等)在导入后可能丢失,但纯文本内容和层级结构保存完好,对于笔记价值来说足够了。
2.2 实操步骤:Python 脚本转换 .km 到 .mm
在 Deepin/UOS 上,Python 环境和pip通常都是预装好的,你需要用pip install安装一个额外库来处理 JSON。不过实际上,.km文件的 JSON 解析可以不依赖第三方库,用 Python 标准库里的json和xml.etree.ElementTree就能完成。
我先解释一下脚本的核心逻辑,你不需要完全看懂每一行,重点是理解整个处理链路:
- 读取
.km文件,用json.load()解析 JSON。 - 从解析结果中取出
content字段,这串字符串就是节点的 XML 文本。 - 直接用
xml.etree.ElementTree.fromstring()解析这串 XML,得到根节点和所有子节点。 - 遍历节点树,生成 FreeMind 格式的 XML 文本,每个
<node>对应 FreeMind 的<node TEXT="...">。 - 把生成的 XML 保存为
.mm文件。
下面是我调试过的完整脚本,你复制到 Deepin/UOS 上,把input.km换成你的文件名,直接运行就能在当前目录生成对应的.mm文件。
import json import xml.etree.ElementTree as ET def km_to_mm(km_file, mm_file): # 第一步:读取 .km 文件并解析 JSON with open(km_file, 'r', encoding='utf-8') as f: data = json.load(f) # 第二步:提取 content 字段中的 XML 字符串 xml_content = data.get('content', '') root = ET.fromstring(xml_content) # 第三步:递归构建 FreeMind 格式的 XML def build_mm_node(node): # 获取节点文本 text = node.get('text', '') or '' # 处理备注(如果有) note = node.find('notes') note_text = '' if note is not None and note.text: note_text = note.text.strip() # 创建 FreeMind 节点 mm_node = ET.Element('node') mm_node.set('TEXT', text) if note_text: note_child = ET.SubElement(mm_node, 'richcontent') note_child.set('TYPE', 'NOTE') html = ET.SubElement(note_child, 'html') body = ET.SubElement(html, 'body') p = ET.SubElement(body, 'p') p.text = note_text # 递归处理子节点 for child in node.findall('node'): mm_node.append(build_mm_node(child)) return mm_node # 创建 FreeMind 根节点 mm_root = ET.Element('map') mm_root.set('version', '1.0.1') # 忽略百度脑图的根节点,直接把它的子节点作为 FreeMind 根节点的子节点 map_node = ET.SubElement(mm_root, 'node') map_node.set('TEXT', root.get('text', '百度脑图迁移')) for child in root.findall('node'): map_node.append(build_mm_node(child)) # 第四步:写入 .mm 文件 tree = ET.ElementTree(mm_root) tree.write(mm_file, encoding='utf-8', xml_declaration=True) print(f'转换完成: {km_file} -> {mm_file}') if __name__ == '__main__': km_to_mm('input.km', 'output.mm')写完后,在终端里执行:
python3 km_to_mm.py如果一切顺利,你会看到当前目录下生成了output.mm文件。这时候还没结束,建议你用文本编辑器打开这个.mm文件,检查一下节点层级是不是符合预期。我遇到过最典型的错误是:乱码。如果.km文件里的文本是 GBK 编码而非 UTF-8,你需要在open()时指定正确的编码。
2.3 思源笔记导入 .mm 的完整流程
打开思源笔记,创建一个新文档或者进到某个笔记本里,点击右上角的“导入”按钮,选择“Markdown”类型是不够的,因为.mm不是 Markdown。你要在文件选择框里把文件类型过滤器切到“所有文件”,然后选中output.mm文件。
思源会识别 FreeMind 格式并自动创建文档结构。导入完成后,你大概率会遇到两个需要手动处理的小问题:
第一个是思源导入.mm时,会把它识别为一个“块”,而不是自动拆分到多个文档。如果你希望每个根节点变成一篇独立笔记,需要手动拆分;如果你只是在单篇笔记里维护这份导图,其实不需要额外操作。
第二个问题是备注内容。FreeMind 的备注会存放在richcontent标签里,思源导入后,备注内容会变成块下方的引用块,样式上不算特别美观,但内容不会丢。我建议你在迁移完成后批量检查一遍备注是否完整,如果有缺失,大概率是原始.km文件里备注字段的编码问题,这时候需要回到脚本里额外处理。
2.4 注意事项:批量转换与文件命名
如果你百度脑图里的文件很多,一个一个跑脚本太痛苦了。可以在脚本外面套一层循环,用glob匹配目录下所有.km文件,批量生成对应的.mm文件。我后来就是这么干的,半小时处理完了前几年的所有历史脑图。
import glob import os for km_file in glob.glob('*.km'): mm_file = km_file.replace('.km', '.mm') print(f'正在转换: {km_file}') km_to_mm(km_file, mm_file)这里有个小提示:.km文件里的根节点名称通常是一串随机的哈希字符串,真正有意义的标题在根节点的子节点里。所以我在转换时特意给 FreeMind 的根节点设置了一个固定的名称“百度脑图迁移”,避免导入思源后出现一串看不懂的文件名。你完全可以把这个名称改成某个有意义的名字,比如“历史归档汇总”。
3. 方法二:通过 Markdown 大纲直接整理
3.1 原理说明:为什么 Markdown 在大纲迁移中更好用
这个方法的核心思路更简单粗暴:既然思源对 Markdown 的标题和列表识别非常稳定,那我们直接把.km节点转成 Markdown 文本,然后复制粘贴进思源,或者作为.md文件导入,剩下的事让思源自动识别。
相比方法一,这条路少了.mm中转环节,也就少了一层格式转换的风险。它的缺点是需要你在思源里创建文档、粘贴内容后手动调整层级,但如果你熟练使用 Markdown 语法,操作起来其实非常快。
我测试后发现,思源对 Markdown 标题的识别非常灵敏,只要你的#符号后面有空格就能识别。所以转换脚本的核心就是把节点深度映射成#的数量:根节点用#,子节点用##,以此类推。
3.2 实操步骤:从 .km 文件提取 Markdown 大纲
这里你可以继续用 Python 脚本,也可以在图里直接复制文本。我先把脚本版放出来,因为它最稳定、最不容易出错。
同样的逻辑,解析.km文件后,遍历节点树,这次不生成 XML,而是生成 Markdown 字符串。每个节点根据深度生成对应数量的#符号和空格,然后是节点文本。备注内容作为引用块跟在节点标题下方。
import json import xml.etree.ElementTree as ET def km_to_markdown(km_file, md_file): with open(km_file, 'r', encoding='utf-8') as f: data = json.load(f) xml_content = data.get('content', '') root = ET.fromstring(xml_content) lines = [] def add_md_node(node, depth): # 当前节点作为标题 text = node.get('text', '') or '' if depth == 0: lines.append(f'# {text}') elif depth == 1: lines.append(f'## {text}') elif depth == 2: lines.append(f'### {text}') elif depth == 3: lines.append(f'#### {text}') else: # 层级太深时,用列表表示 prefix = ' ' * (depth - 4) + '- ' lines.append(f'{prefix}{text}') # 备注作为引用块 note = node.find('notes') if note is not None and note.text: note_text = note.text.strip() lines.append('') lines.append(f'> {note_text}') # 递归处理子节点 for child in node.findall('node'): add_md_node(child, depth + 1) # 根节点 depth=0,但实际根节点本身不需要一级标题,把子节点作为一级标题 for child in root.findall('node'): add_md_node(child, 1) with open(md_file, 'w', encoding='utf-8') as f: f.write('\n'.join(lines)) print(f'Markdown 文件已生成: {md_file}') if __name__ == '__main__': km_to_markdown('input.km', 'output.md')执行完脚本后,你得到的output.md文件就是一份纯文本的大纲。在思源笔记里新建一篇文档,全选复制粘贴进去,思源会自动识别#标题并生成大纲结构。如果你更倾向于文件导入,也可以直接在思源里导入这个.md文件,效果是一样的。
3.3 手动整理法:不写一行代码的迁移方案
如果不想用 Python,或者你手上的导图数量很少,完全可以手动操作。在百度脑图网页端,直接按Ctrl+A全选节点内容,然后Ctrl+C复制,接着打开系统的文本编辑器,Ctrl+V粘贴。
你会看到粘贴出来的文本是按 Tab 缩进的纯文本列表,每个缩进层级代表一个层级。利用 Deepin 自带的文本编辑器或 VS Code,你可以快速用正则把 Tab 替换成#:比如把一行开头的 4 个空格替换成##,把 8 个空格替换成###,以此类推。
这个方法的好处是你能完全控制标题的命名和层级,在替换过程中顺手清理无效节点、重命名标题,相当于在做一次数据清洗。缺点是手动操作容易出错,尤其是层级较多时,建议替换完后在思源里预览一遍,缩进不对的地方直接手动修正。
3.4 两种导入方式的体验对比
把 Markdown 粘贴进思源和通过.md文件导入,两者在结果上几乎没有区别,但体验上略有不同:
| 导入方式 | 操作速度 | 链路环节 | 适用场景 |
|---|---|---|---|
| 复制粘贴 | 快 | 一步到位 | 单篇文档、量少的场景 |
| 文件导入 | 略慢 | 需要先存文件再导入 | 批量导入、需要归档原文件的场景 |
我自己习惯是:文件导入,因为.km和.md文件我可以一起留在工作目录里,方便以后回溯。如果你只是临时迁移一两篇,粘贴就够了,没必要多一个文件流程。
4. 迁移后的内容清洗与结构优化
4.1 处理丢失的链接、图片与格式信息
不管你用方法一还是方法二,迁移完成后都会有信息损失。这是我在多个平台之间迁移数据后总结出的通识教训:除非源平台提供完美的 API 对接,否则样式类信息和多媒体信息几乎必然丢失。百度脑图里的超链接在转换成.mm或 Markdown 时,会变成纯文本,图片也是同样的情况。
应对策略分两步走。第一步,在百度脑图导出前,把导图里重要的超链接地址单独复制一份到文本文件里留存;第二步,在思源里通过“全局搜索”定位到相关笔记,然后手动补充链接。如果你嫌麻烦,也可以接受链接丢失,前提是你迁移的内容偏向思路整理而非资料收藏。
补充一个小技巧:百度脑图支持把图片放在节点里,但导出的.km文件里图片信息极难解析,我在脚本里直接忽略了。如果你的导图有大量图片素材,我的建议是不要用这两种方法迁移图片,直接在思源里用更可靠的方案重建,比如把图片拖进思源工作空间后,再通过引用链接挂接到对应的笔记块。
4.2 借用思源模板优化迁移后的结构
思源笔记另一个让我觉得很实用的功能是模板。迁移完导图后,你可以在“设置 → 模板”里新建一个“脑图归档模板”,包含几个固定区块:来源链接、迁移时间、关键词标签、备注区。这样每次导入新的导图后,手动把信息填进模板区块,笔记就变得规范化了。
我自己的模板是这样的:
# 来源信息 - 原平台:百度脑图 - 迁移时间:{{today}} - 原文件备份路径:/mnt/data/backup/xxx.km # 内容备注 - 标签:{{tags}}这个模板配合思源的“日记”功能特别好用。我会把每周迁移的脑图都汇总到当天的日记里,形成一条清晰的记录线。
4.3 批量导入时如何保持关联与层级完整
如果你一次要迁移几十个脑图,建议不要直接导入到一个笔记本里,而是按主题分笔记本导入:比如“工作项目”“读书笔记”“生活规划”各自建一个笔记本,把相应的导图导入进去。这样后续检索和知识管理会轻松很多。
层级这块,思源的“文档树”如果太深反而不好用,我一般控制在三层以内:笔记本 → 文档 → 子文档。层级太深的话,后续找内容会很难受,而且思源的“反链”功能最佳发挥场景是浅层级结构。
如果你导入后发现思源的文档树层级太深,一个简单粗暴的方法是先在思源里把层级拆分成多篇文档,然后把原来的文档作为“汇总页”,用链接把子文档串起来。这种方式比维护一颗深树结构好用得多。
5. 常见问题与排查技巧实录
5.1 乱码与编码问题
这是我在迁移过程中遇到最多的一个问题,尤其是在百度脑图早期创建的导图里。Deepin/UOS 上文本编辑器默认是 UTF-8 编码,但百度脑图导出的.km文件有一部分是 GBK/GB18030 编码,直接用 Python 的json.load()读取会在第一步就崩溃,报错信息大概是UnicodeDecodeError或者json.decoder.JSONDecodeError。
解决办法是在读取文件时指定编码。把打开文件的那行代码改成:
with open(km_file, 'r', encoding='gb18030') as f: data = json.load(f)如果不知道文件是 UTF-8 还是 GBK,可以在 Deepin/UOS 上先用file命令查看文件编码:
file input.km如果显示ISO-8859或者unknown-8bit,基本可以断定是 GBK 编码,不需要猜,直接用gb18030读取最稳。
5.2 导入思源后层级丢失
用方法一导入.mm后,如果你发现思源只显示了部分层级,或者某些子节点变成了“折叠块”,大概率是 FreeMind 的 XML 结构里存在“折叠组”或“云彩”等特殊节点类型,这类节点在思源的导入器里会被过滤掉。解决办法是在转换脚本里,跳过那些没有TEXT属性的空节点。
如果你用的是方法二(Markdown),出现层级丢失通常是因为原始节点文本里包含#、*、_等 Markdown 特殊字符,这些字符在粘贴进思源后被解析成了 Markdown 语法。解决办法是在脚本里给这些特殊字符前面加上\转义,或者在粘贴时选择“纯文本粘贴”后再重新调整标题。
5.3 备份与断点续传
迁移过程中我踩过最大的坑是:一次性处理大量文件时,脚本跑到一半崩了,前面处理完的也忘了备份,结果要重新来一遍。所以无论你选择哪条方法,第一步永远是备份原始.km文件。在 Deepin/UOS 上最简单的办法:
mkdir -p ~/baidu-naotu-backup cp *.km ~/baidu-naotu-backup/我建议把备份目录放到独立数据盘或挂载点下,不要和系统分区混在一起,万一系统重装或磁盘故障,备份不会跟着丢。UOS 用户如果在“文件管理器”里看到某些备份文件带小锁标志,那是权限问题,用chmod 644或者图形界面的属性设置把权限放开就行。
5.4 常见错误速查表
| 错误现象 | 可能原因 | 解决办法 |
|---|---|---|
Python 报UnicodeDecodeError | .km是 GBK 编码 | 改用gb18030编码读取 |
脚本正常执行但生成空的.mm | content字段提取失败 | 检查.km文件是否为百度脑图标准导出格式 |
| 导入思源后只有一个根节点 | XML 解析只取了根节点 | 在脚本中检查findall('node')的层级是否正确 |
| 粘贴 Markdown 后标题没有层级 | 复制的文本里空格/制表符类型不对 | 先在文本编辑器中统一替换成标准 Markdown#格式 |
| 备注内容丢失 | .km中备注字段命名不同 | 检查原始 XML 中备注对应的标签名,调整脚本中的find |
6. 迁移完成后的使用建议
6.1 建立本地与在线双写工作流
迁移完成后,我并没有完全抛弃百度脑图。说实话,百度脑图在手机端的轻量查看和快速编辑上是本地软件比不了的。我现在的工作流是:在线快速构思用百度脑图,定稿后导出一份.km归档,有时间就转成 Markdown 推送到思源。这样既保留了在线工具的便利性,又让思源成为我的知识沉淀中心。
在 Deepin/UOS 上我用的是坚果云和 WebDAV 做思源工作空间的同步,这样就算换了机器,思源数据也能无缝恢复。这个方案和 Deepin/UOS 的兼容性很好,同步过程中没有遇到文件锁冲突的问题。
6.2 利用思源双链增强导图笔记的价值
单纯的思维导图导入思源,其实只完成了迁移的一半。思源真正的价值在于双链和块引用。我建议在迁移完成后,给每一篇导图笔记打上主题标签,并手动添加几个关键双链,把导图与已有的项目文档关联起来。比如你有一个“产品规划”的导图,就在笔记里用[[产品路线图]]、[[2026年规划]]这样的双链指向相关文档。
这样处理后,思源的“关系图”面板会慢慢长出节点网络,这是百度脑图给不了的体验,也是我迁移数据的深层动力所在。
6.3 定期导出归档避免再次陷入被动
在百度脑图里待了好几年,突然要迁移时发现自己对平台产生了依赖,这种感觉很被动。所以现在我有固定的归档习惯:每个季度末,把思源工作空间导出一次 zip 包,同时把导出的 Markdown 文件复制到移动硬盘。这样就算哪一天思源也出了问题,我手里永远有一份完全离线、不依赖任何服务和账号的纯文本数据。
写在最后
如果你问我在 Deepin/UOS 上迁移百度脑图到思源笔记,到底用方法一还是方法二,我的答案是:方法二优先。不是说方法一不好,而是在实际操作中,方法二的中间环节更少、可控性更强,长期维护也更省心。我自己最终是把所有历史导图都用脚本转成了 Markdown,然后按主题分笔记本导入到思源,整个过程大概花了两个晚上,其中大半时间花在排查编码问题上。
再分享一个小技巧:无论用哪种方法,导入完成后别急着删源文件。把.km原始文件和转换后的.md/.mm文件放在同一个目录,命名保持一致,这就是你未来所有笔记数据的“底片”。有了这层底片,之后你再想换到别的笔记工具,也只是一次脚本执行的事,而不用再回到网页端去手动导出。
数据在自己手里,才是最踏实的。