自打主力机换成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 结构。你不需要完全看懂每一个字段但至少要知道根节点在哪、子节点是怎么嵌套的这对后边两种方法的选择会有直接影响。另外百度脑图还支持导出.mmFreeMind 标准格式、.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, encodingutf-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, encodingutf-8, xml_declarationTrue) 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, encodingutf-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) # 根节点 depth0但实际根节点本身不需要一级标题把子节点作为一级标题 for child in root.findall(node): add_md_node(child, 1) with open(md_file, w, encodingutf-8) as f: f.write(\n.join(lines)) print(fMarkdown 文件已生成: {md_file}) if __name__ __main__: km_to_markdown(input.km, output.md)执行完脚本后你得到的output.md文件就是一份纯文本的大纲。在思源笔记里新建一篇文档全选复制粘贴进去思源会自动识别#标题并生成大纲结构。如果你更倾向于文件导入也可以直接在思源里导入这个.md文件效果是一样的。3.3 手动整理法不写一行代码的迁移方案如果不想用 Python或者你手上的导图数量很少完全可以手动操作。在百度脑图网页端直接按CtrlA全选节点内容然后CtrlC复制接着打开系统的文本编辑器CtrlV粘贴。你会看到粘贴出来的文本是按 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, encodinggb18030) 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编码读取脚本正常执行但生成空的.mmcontent字段提取失败检查.km文件是否为百度脑图标准导出格式导入思源后只有一个根节点XML 解析只取了根节点在脚本中检查findall(node)的层级是否正确粘贴 Markdown 后标题没有层级复制的文本里空格/制表符类型不对先在文本编辑器中统一替换成标准 Markdown#格式备注内容丢失.km中备注字段命名不同检查原始 XML 中备注对应的标签名调整脚本中的find6. 迁移完成后的使用建议6.1 建立本地与在线双写工作流迁移完成后我并没有完全抛弃百度脑图。说实话百度脑图在手机端的轻量查看和快速编辑上是本地软件比不了的。我现在的工作流是在线快速构思用百度脑图定稿后导出一份.km归档有时间就转成 Markdown 推送到思源。这样既保留了在线工具的便利性又让思源成为我的知识沉淀中心。在 Deepin/UOS 上我用的是坚果云和 WebDAV 做思源工作空间的同步这样就算换了机器思源数据也能无缝恢复。这个方案和 Deepin/UOS 的兼容性很好同步过程中没有遇到文件锁冲突的问题。6.2 利用思源双链增强导图笔记的价值单纯的思维导图导入思源其实只完成了迁移的一半。思源真正的价值在于双链和块引用。我建议在迁移完成后给每一篇导图笔记打上主题标签并手动添加几个关键双链把导图与已有的项目文档关联起来。比如你有一个“产品规划”的导图就在笔记里用[[产品路线图]]、[[2026年规划]]这样的双链指向相关文档。这样处理后思源的“关系图”面板会慢慢长出节点网络这是百度脑图给不了的体验也是我迁移数据的深层动力所在。6.3 定期导出归档避免再次陷入被动在百度脑图里待了好几年突然要迁移时发现自己对平台产生了依赖这种感觉很被动。所以现在我有固定的归档习惯每个季度末把思源工作空间导出一次 zip 包同时把导出的 Markdown 文件复制到移动硬盘。这样就算哪一天思源也出了问题我手里永远有一份完全离线、不依赖任何服务和账号的纯文本数据。写在最后如果你问我在 Deepin/UOS 上迁移百度脑图到思源笔记到底用方法一还是方法二我的答案是方法二优先。不是说方法一不好而是在实际操作中方法二的中间环节更少、可控性更强长期维护也更省心。我自己最终是把所有历史导图都用脚本转成了 Markdown然后按主题分笔记本导入到思源整个过程大概花了两个晚上其中大半时间花在排查编码问题上。再分享一个小技巧无论用哪种方法导入完成后别急着删源文件。把.km原始文件和转换后的.md/.mm文件放在同一个目录命名保持一致这就是你未来所有笔记数据的“底片”。有了这层底片之后你再想换到别的笔记工具也只是一次脚本执行的事而不用再回到网页端去手动导出。数据在自己手里才是最踏实的。
