Google Keep 笔记迁移指南:Takeout 导出转 Markdown
Keep 里的笔记要搬进 blog(或者 Obsidian),路线是固定的:Takeout 导出 → 脚本转换。全程不需要任何第三方服务碰你的数据。
Step 1:Takeout 导出
- 打开 takeout.google.com;
- 先点「取消全选」,然后只勾选 Keep;
- 导出格式选 zip,创建导出 —— 笔记不多的话几分钟邮件就到。

Keep 的所有内容(包括图片附件和清单勾选状态)都会进 Takeout 包
Step 2:看懂导出内容
解压后每条笔记有两个文件:.html(阅读用)和 .json(转换用)。JSON 结构大致是:
{
"title": "FortiGate HA 心跳口配置",
"textContent": "笔记正文……",
"labels": [{ "name": "networking" }],
"isTrashed": false,
"isArchived": false,
"userEditedTimestampUsec": 1719800000000000
}
几个要点:
- 普通笔记正文在
textContent,清单类笔记在listContent(数组,每项有text和isChecked); isTrashed: true的是回收站里的,转换时要跳过;- 图片附件在
attachments,文件就在同一个文件夹里; - Keep 的标签(labels)可以直接映射成 blog 的 tags。
Step 3:批量转换脚本
核心逻辑就几十行 Node(放在 scripts/keep2md.mjs 之类的位置):
import fs from 'node:fs';
import path from 'node:path';
const src = './Takeout/Keep';
const out = './inbox';
for (const f of fs.readdirSync(src).filter(f => f.endsWith('.json'))) {
const note = JSON.parse(fs.readFileSync(path.join(src, f), 'utf8'));
if (note.isTrashed) continue;
const date = new Date(note.userEditedTimestampUsec / 1000)
.toISOString().slice(0, 10);
const tags = (note.labels ?? []).map(l => l.name);
const body = note.textContent
?? (note.listContent ?? [])
.map(i => `- [${i.isChecked ? 'x' : ' '}] ${i.text}`)
.join('\n');
const md = `---\ntitle: ${note.title || '(untitled)'}\ndate: ${date}\ntags: [${tags.join(', ')}]\ndraft: true\n---\n\n${body}\n`;
fs.writeFileSync(path.join(out, f.replace('.json', '.md')), md);
}
所有产出先进 inbox/ 并且默认 draft: true —— 转换是批量的,筛选是人工的。值得发布的挪进 src/content/posts/,其余留着当私人档案。
教训预告
Keep 的笔记普遍是「一句话备忘」,真正能成文的可能只有两三成。别指望全自动,转换只是把原料备好。