OneNote (.onepkg) → PDF/Markdown → ima
Overview
把 OneNote 导出的 .onepkg 笔记本,按「笔记本 / 分区组 / 分区 / 页面」的层级
批量转成 PDF(默认,图片内嵌) 或 Markdown,供 ima 知识库通过
「导入 → 本地文件夹」批量入库。
何时使用
- 用户想把 OneNote 笔记导入 ima(或其他知识库);
- 用户手上有
.onepkg文件需要批量转换; - 用户问 OneNote 笔记怎么迁移 / 备份成通用格式。
关键事实(不要凭常识猜)
- ima 没有 OneNote 导入通道,只能走「PDF/Markdown → 知识库 → 导入 → 本地文件夹」;
- OneNote for Windows 10(应用商店版)自 2025-10-14 起只读,需从 OneNote 网页版
或 OneNote 2016 桌面版导出.onepkg; .onepkg是 CAB 包,不是 zip;- 用户常见默认目录:输入
D:\onepkg,PDF 输出D:\onepdf,Markdown 输出D:\onemd。
标准流程
第 1 步:准备源文件
提示用户把笔记本逐个导出为 .onepkg,或直接从 OneNote 缓存/备份里拷出 .one 分区文件,
统一放入一个目录(默认 D:\onepkg)。两种输入都支持:
- *.onepkg:完整笔记本包(推荐,保留分区组层级);
- *.one:单个分区文件,会被归到 OneNote分区文件 目录下(--notebook-name 可改名)。
先确认目录里存在这两类文件之一再继续。
第 2 步:部署依赖
python scripts/setup_env.py --check # 先看缺什么
python scripts/setup_env.py # 装缺失项(全部便携版,免管理员)
四样依赖:onenote-tool[cli](pip)、7-Zip、wkhtmltopdf(PDF 用)、pandoc(Markdown 用)。
setup_env.py 会自动探测、下载便携版,并用 winget 尝试安装 7-Zip;
装不上的会给出手动安装链接。
第 3 步:转换
python scripts/convert_onepkg.py # D:\onepkg -> D:\onepdf (PDF,默认)
python scripts/convert_onepkg.py --format md # -> D:\onemd
python scripts/convert_onepkg.py --format both # -> D:\onenote_out
python scripts/convert_onepkg.py D:\src D:\out --format pdf
python scripts/convert_onepkg.py --no-dedup # 保留重复页(默认会去重)
python scripts/convert_onepkg.py --check # 只检查环境不转换
python scripts/convert_onepkg.py D:\src D:\out --format pdf --notebook-name 投资 # 散装 .one 命名
python scripts/convert_onepkg.py --work-dir D:\_mytest # 指定中间产物目录
python scripts/convert_onepkg.py --no-keep-html # 不保留逐页 HTML(默认保留)
中间产物(渲染用 HTML、解包/解析工作目录)统一落在独立目录里:
默认是源文件所在磁盘根目录的单一文件夹 _onenote_debug\intermediates
(如 D:\_onenote_debug\intermediates),不会产生一堆散落在盘符根下的 _xxx 目录,
全程只增不删、不进回收站,方便事后检查;可用 --work-dir 或环境变量
ONENOTE_WORK_DIR 覆盖。切勿再改成"落临时目录再删"。
纯 .one 输入不需要 7-Zip(不解 CAB),缺 7-Zip 也能跑。
不熟悉命令行的用户:直接双击 scripts/run_convert.py,会进入交互式向导
(依次询问 .onepkg 目录 → 输出格式 → 输出目录 → 是否去重,一路回车即用默认值),
结束后窗口会等一个回车再关闭。也可带参数使用,参数与 convert_onepkg.py 完全一致:
python scripts/run_convert.py --check
python scripts/run_convert.py D:\onepkg D:\onepdf --format pdf
注意:技能市场不允许发布 .bat 文件,因此不要再生成 .bat 启动器,统一用 run_convert.py。
第 4 步:核对结果
- 分区数量要与 OneNote 里的分册数量一致(不一致看排错表第 1 条);
- 确认没有
_2/_3之类残留重复文件; - 抽查 PDF 中文与图片:
python from pypdf import PdfReader print(PdfReader(r"D:\onepdf\xxx.pdf").pages[0].extract_text()[:200])
第 5 步:导入 ima
按 references/ima-import.md:ima → 知识库 → 导入 → 本地文件夹,
每批 20 个文件以内,按分区子目录分批。
脚本已内建的处理(勿重复造轮子)
scripts/convert_onepkg.py 已处理这些 OneNote 特有问题:
- 7-Zip 接管 CAB 解包(系统
expand.exe解不开中文文件名); - 修复被吃掉的扩展名(
青岛政策与信息.one→..._one,会导致整个分区被漏掉); - 用 onetoc2 里的 UTF-16LE 真实名还原乱码分区 / 页面名;
- 两级去重:内容哈希去重 + 同标题保留正文最长的一份;
- 只增不删(v1.2.0 起):重跑时同名文件直接覆盖,不清空旧目录 —— 全程无任何
os.remove/shutil.rmtree,不会触发沙箱的批量删除守卫;
中间 HTML 不再落在输出目录乱成一锅,而是集中到独立的中间产物目录; - PDF 图片以 base64 内嵌,中文字体正常;
- 图片预处理:按正文宽度等比缩放,并把网页长截图(宽约 900、高 4000~7000)
切成多块顺序渲染 —— 既避开渲染引擎的画布上限,也避免被压成不可读的窄条; - 渲染三级降级链:标准 → 图片再压缩 → Chromium 引擎(若本机有 Edge/Chrome)
→ 去图纯文字;单页失败只跳过该页,不中断整本。
需要改脚本或排查异常时,先读 references/pitfalls.md
(含 onenote-tool API、CAB / onetoc2 二进制格式、mojibake 还原算法、bat 编码坑等全部细节)。
排错速查
| 现象 | 原因 / 处理 |
|---|---|
| 分区数比分册少 | 扩展名被吃(_one);脚本已修,仍缺则看 pitfalls.md 第 4 节 |
| 分区名 / 标题是乱码 | 有 onetoc2 时靠它还原;没有 onetoc2(单分区导出)时改为从 .one 文件内部(UTF-16LE)读真实名,见 pitfalls.md 第 4.5 节 |
| 生成数量与磁盘文件数不一致 | 文件名冲突被覆盖或旧输出残留;先删输出目录再跑 |
| PDF 里中文是方块 | wkhtmltopdf 版本太旧或 CSS 字体缺失;用 0.12.6 便携版 |
| PDF 里没图 | 图片未走 base64 内嵌;确认走的是 PDF 分支的 _embed_images |
.bat 被市场审核拒收 |
市场不允许发布 .bat;改用 scripts/run_convert.py(双击同样可用) |
报错 path is on mount 'D:', start on mount 'C:' |
散装 .one 的工作目录必须与其同盘符;已用 dir= 锚定,勿改回默认 tempdir |
输出里多出 _ / __ 层级 |
.one 场景下库算出的 group_path 是 ..;已过滤无效层级,勿删该过滤 |
目录里只有 .one 却提示没找到文件 |
检查扩展名大小写与后缀拼写(必须是 .one 不是 .onepkg) |
大批量跑到几十页报 SAFE_DELETE_BULK_CONFIRM_REQUIRED |
沙箱批量删除守卫(阈值约 50 次删除)。必须用 v1.2.0+ 的零删除版本;不要改回"先写临时 HTML 再删除"或"转换前 rmtree 清空输出目录" |
输出目录里出现 _html_archive / xxx_old_1234 |
旧版"挪走代替删除"留下的归档,体积可达数 GB;v1.2.0 已不再产生,旧目录可手动清理 |
| 某页渲染失败被跳过 | 先看日志里的降级行。多数是「标准→图片再压缩→去图」四选一能救回;想更强兜底就装 Chrome/Edge 或用 ONENOTE_CHROMIUM 指定路径,见 pitfalls.md 第 9 节 |
| 页面能出 PDF 但图片是糊窄条 | 说明走了"最长边缩放"的旧策略;v1.3.0 起改为按正文宽度缩放 + 长图切片 |
报 ContentNotFoundError / ProtocolUnknownError |
HTML 里残留外链或 onenote-image:// 占位符。已固定加 --load-error-handling ignore;若还报,检查 _embed_images 是否覆盖了全部 images/files |
| 没找到备用渲染引擎 | 本机无 Edge/Chrome,属正常;wkhtmltopdf + 降级链仍可完成绝大多数页面 |
整本笔记本被跳过(NameError / 其他异常) |
v1.2.0 起单页异常已隔离;若整本被跳过,看日志里的 处理异常 行定位 |
| 下载依赖失败 | GitHub TLS 吊销检查失败;用 curl --ssl-no-revoke(setup_env.py 已实现) |
| 转换后仍有大量重复 | 确认没加 --no-dedup,且输出目录已清空再跑 |
提示 onenote-tool : 未安装 |
依赖装在被清空/换掉的 Python 环境里了。用哪个解释器跑脚本,就用哪个解释器装包:python -m pip install "onenote-tool[cli]" pillow beautifulsoup4 lxml html2text pypdf(或运行 scripts/setup_env.py) |
分区/笔记本目录名是乱码(如 鎬濊_、浜__氫笌鏃呮父) |
源 .onepkg 缺 onetoc2 时分区名来自 GBK 乱码;v1.3.4 已能还原含 € 的那类(如 思考)。若仍乱码,说明源文件里末字节真的丢了,属硬限制 —— 只影响文件夹名,PDF 文件名与正文不受影响 |
文件名里的中文莫名消失(如 星期五, 六月 15, 2018 变成 _ 15_ 2018) |
recover() 把干净中文越修越糟;v1.3.3 起只对严格 X->utf-8 解码出的候选生效,干净标题原样保留 |
出现两个同名文件被加了 _2 |
不是重复文件 —— 是原标题被 recover() 破坏后撞名(如两个不同日期页都变成 _ 6_ 2018);v1.3.3 已修 recover(),撞名会随之中止 |
某页报 QPainter::begin(): Returned false 且每种策略都失败 |
不是图片太大(去图后的纯文字页照样失败)。真凶是文件名里含 Ѽ 之类西里尔字母(乱码还原的副产物),wkhtmltopdf 会把它当成没有协议头的 URL 而崩溃 —— v1.3.2 起 safe_name() 改用白名单,已根治 |
日志出现 Factory: URL has no schema set, use file:// for files |
同上,直接证据指向 HTML 文件名有毒,不要再往"页面太大"方向排查 |
| 日志出现「营救重试(退避 Ns 后文件模式)」 | 说明走了 v1.3.2 的最终营救,页面已成功救回,无需处理 |
盘符根目录下冒出一堆 _xxx 目录 |
v1.3.1 起中间产物全部收进 _onenote_debug\intermediates 单一文件夹;旧的散目录可直接移入 _onenote_debug 统一管理 |
Resources
scripts/convert_onepkg.py— 主转换脚本(PDF/Markdown,去重,中文修复)scripts/setup_env.py— 依赖一键部署 / 检查scripts/run_convert.py— 交互式启动器(双击即用,也可带参数;替代 .bat)references/pitfalls.md— 技术细节与踩坑记录references/ima-import.md— ima 导入操作说明与替代方案