有道云笔记作为一款常用的云端笔记工具,承载了我们大量的资料和创作。然而,其在内容复制、文章目录显示等方面的一些限制,有时会给我们的使用带来不便。为了更自由地管理和迁移我的笔记,我找到了将笔记导出为通用 Markdown 格式的方法。

本文将介绍两种行之有效的方法:

  1. 油猴脚本:适合单篇笔记的即时导出,尤其适用于那些经常需要修改和分享的文章。
  2. Python 脚本:一个功能强大的批量导出方案,适合一次性备份或迁移全部笔记。

方法一:使用油猴脚本(单篇、即时导出)

这个方法通过在浏览器中安装一个简单的脚本,为你的有道云笔记分享页面增加一个“导出为 MD”的按钮,实现一键下载。

1. 安装油猴(Tampermonkey)扩展

油猴是一款强大的浏览器扩展,它允许用户运行自定义脚本来增强网页功能。

国内用户建议选择第二个或第三个链接进行安装

2. 导入导出脚本

安装好油猴扩展后,你有两种方式来导入脚本

方式 A:直接安装 (推荐)

直接点击下方链接即可一键安装:
-> 国外 点击此处安装脚本
-> 国内 点击此处安装脚本

方式 B:手动创建 (备用方案)

如果无法访问上述链接,请按以下步骤手动创建脚本:

  1. 在浏览器右上角找到“篡改猴”扩展图标,点击它,然后选择“添加新脚本”。
    在浏览器右上角找到篡改猴扩展
    选择添加新脚本的选项

  2. 在打开的编辑器页面中,清空所有默认内容,然后将下面的完整代码粘贴进去。
    将下面的脚本代码粘贴到编辑区域

  3. 按下 Ctrl + S 保存脚本,即可完成安装。

脚本代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// ==UserScript==
// @name 有道云笔记导出为markdown
// @name:en Youdao Note Exporter to Markdown
// @namespace https://github.com/your-username/youdao-note-exporter
// @version 3.0
// @description 在有道云笔记分享页面添加一个按钮,用于将笔记内容导出为Markdown文件。智能识别富文本和Markdown两种页面类型并进行相应处理。
// @description:en Add a button on Youdao Note share pages to export content as a Markdown file. Intelligently handles both rich text and Markdown note types.
// @author SkyForever
// @match https://share.note.youdao.com/*
// @match https://note.youdao.com/ynoteshare/*
// @grant none
// @license MIT
// @downloadURL https://update.greasyfork.org/scripts/550754/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0%E5%AF%BC%E5%87%BA%E4%B8%BAmarkdown.user.js
// @updateURL https://update.greasyfork.org/scripts/550754/%E6%9C%89%E9%81%93%E4%BA%91%E7%AC%94%E8%AE%B0%E5%AF%BC%E5%87%BA%E4%B8%BAmarkdown.meta.js
// ==/UserScript==

(function () {
"use strict";

// --- 富文本解析模块 (旧版页面) ---
const richTextParser = {
parseNode: function (node) {
if (node.nodeType === 3) return node.textContent;
if (node.nodeType !== 1) return "";

let innerMarkdown = Array.from(node.childNodes)
.map((child) => this.parseNode(child))
.join("");
const isBold =
node.style.fontWeight === "bold" || node.classList.contains("bold");
if (isBold && innerMarkdown.trim() !== "") {
if (!innerMarkdown.startsWith("**") && !innerMarkdown.endsWith("**")) {
innerMarkdown = `**${innerMarkdown}**`;
}
}
if (node.tagName.toLowerCase() === "a" && node.hasAttribute("href")) {
return `[${innerMarkdown}](${node.getAttribute("href")})`;
}
if (node.tagName.toLowerCase() === "br") {
return "\n";
}
return innerMarkdown;
},

convertHeading: function (block) {
const level = parseInt(block.dataset.headingLevel.replace("h", ""), 10);
return `${"#".repeat(level)} ${this.parseNode(block).trim()}`;
},

convertParagraph: function (block) {
const text = this.parseNode(block).trim();
return text === "" &&
(block.innerHTML.includes(" ") || block.textContent.trim() === "")
? ""
: text;
},

convertImage: function (block) {
const img = block.querySelector("img");
return img ? `![image](${img.getAttribute("src")})` : "";
},

convertListItem: function (block) {
const li = block.querySelector("li");
if (!li) return null;
const text = this.parseNode(li).trim();
let prefix = "* ";
const placeholder = block.querySelector(".item-list-placeholder");
let indent = "";
if (placeholder && placeholder.style.left) {
const left = parseInt(placeholder.style.left, 10);
if (left > 0) indent = " ".repeat(Math.round(left / 28));
}
if (block.hasAttribute("start")) {
prefix = `${placeholder ? placeholder.textContent.trim() : "1."} `;
}
return `${indent}${prefix}${text}`;
},

convertCodeBlock: function (block) {
const langElement = block.querySelector(".change-language .css-u30aqu");
const lang = langElement
? langElement.textContent.trim().toLowerCase()
: "";
const codeLines = Array.from(
block.querySelectorAll('pre[data-block-type="code-line"]')
).map((pre) => pre.textContent);
return `\`\`\`${lang}\n${codeLines.join("\n")}\n\`\`\``;
},

run: function (editor) {
const blocks = Array.from(editor.children);
const markdownLines = [];
blocks.forEach((block) => {
let mdLine = null;
const blockType = block.dataset.blockType;
if (block.tagName.toLowerCase() === "ul" && blockType === "list-item") {
mdLine = this.convertListItem(block);
} else {
switch (blockType) {
case "heading":
mdLine = this.convertHeading(block);
break;
case "paragraph":
mdLine = this.convertParagraph(block);
break;
case "image":
mdLine = this.convertImage(block);
break;
case "code":
mdLine = this.convertCodeBlock(block);
break;
default:
if (block.textContent && block.textContent.trim()) {
mdLine = this.parseNode(block);
}
break;
}
}
if (mdLine !== null) markdownLines.push(mdLine);
});
return formatMarkdownOutput(markdownLines);
},
};

// --- Markdown 原生页面解析模块 (新版页面) ---
const markdownParser = {
// 由于是原生Markdown渲染,直接从HTML标签转换
run: function (editor) {
const TurndownService =
window.TurndownService ||
(function () {
// 内联一个简化的turndown版本或提示用户安装
alert(
"Turndown library not found. Please add `@require https://unpkg.com/turndown/dist/turndown.js` to the script header."
);
return function () {
this.turndown = (text) => text;
};
})();
const turndownService = new TurndownService({ codeBlockStyle: "fenced" });
return turndownService.turndown(editor.innerHTML);
},
};

/**
* 格式化Markdown输出,处理换行
*/
function formatMarkdownOutput(lines) {
let fullMarkdown = "";
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === "" && (i === 0 || lines[i - 1].trim() === ""))
continue;
fullMarkdown += lines[i];
const isCurrentList = /^((\s*[-*]|\s*\d+\.)\s)/.test(lines[i]);
const isNextList =
i + 1 < lines.length && /^((\s*[-*]|\s*\d+\.)\s)/.test(lines[i + 1]);
fullMarkdown += isCurrentList && isNextList ? "\n" : "\n\n";
}
return fullMarkdown.trim();
}

/**
* 主导出函数
*/
function exportToMarkdown() {
const iframe = document.getElementById("content-body");
if (!iframe) {
alert("错误:未找到笔记内容的iframe框架!");
return;
}

const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (!iframeDoc) {
alert("错误:无法访问iframe的文档内容!");
return;
}

let markdownContent = "";
const noteTitle =
document.querySelector(".file-name")?.title || "youdao-note";

// 判断页面类型
if (iframeDoc.querySelector(".bulb-editor-inner")) {
// 旧版富文本
console.log("检测到富文本笔记,使用富文本解析器。");
const editor = iframeDoc.querySelector(".bulb-editor-inner");
markdownContent = richTextParser.run(editor);
} else if (iframeDoc.querySelector(".markdown-body")) {
// 新版Markdown
console.log("检测到Markdown笔记,使用Turndown解析器。");
// 动态加载turndown库
loadScript("https://unpkg.com/turndown/dist/turndown.js", () => {
const editor = iframeDoc.querySelector(".markdown-body");
markdownContent = markdownParser.run(editor);
downloadMarkdown(markdownContent, noteTitle);
});
return; // 异步执行,直接返回
} else {
alert("错误:未识别的笔记类型或内容未加载!");
return;
}

downloadMarkdown(markdownContent, noteTitle);
}

/**
* 统一的下载处理函数
*/
function downloadMarkdown(content, title) {
const safeFilename =
title.replace(/[\\/:*?"<>|]/g, "-").replace(/\s+/g, "_") || "youdao-note";
downloadFile(content, `${safeFilename}.md`);
}

/**
* 下载文件工具函数
*/
function downloadFile(content, filename) {
const blob = new Blob([content], { type: "text/markdown;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}

/**
* 动态加载外部JS脚本
*/
function loadScript(url, callback) {
if (window.TurndownService) {
// 如果已加载,直接回调
callback();
return;
}
const script = document.createElement("script");
script.src = url;
script.onload = callback;
script.onerror = () =>
alert("加载Turndown库失败,请检查网络连接或脚本设置。");
document.head.appendChild(script);
}

/**
* 在页面上创建并添加导出按钮
*/
function addExportButton() {
if (document.getElementById("export-md-button")) return;

const button = document.createElement("button");
button.id = "export-md-button";
button.textContent = "导出为MD";
button.style.position = "fixed";
button.style.bottom = "20px";
button.style.right = "20px";
button.style.zIndex = "9999";
button.style.padding = "10px 15px";
button.style.backgroundColor = "#4CAF50";
button.style.color = "white";
button.style.border = "none";
button.style.borderRadius = "5px";
button.style.cursor = "pointer";
button.style.fontSize = "14px";
button.style.boxShadow = "0 2px 5px rgba(0,0,0,0.2)";

button.addEventListener(
"mouseover",
() => (button.style.backgroundColor = "#45a049")
);
button.addEventListener(
"mouseout",
() => (button.style.backgroundColor = "#4CAF50")
);
button.addEventListener("click", exportToMarkdown);

document.body.appendChild(button);
}

// 使用MutationObserver来监控DOM变化,确保iframe加载后能及时添加按钮
const observer = new MutationObserver((mutations, obs) => {
const iframe = document.getElementById("content-body");
if (iframe) {
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
if (
iframeDoc &&
(iframeDoc.querySelector(".bulb-editor-inner") ||
iframeDoc.querySelector(".markdown-body"))
) {
addExportButton();
obs.disconnect(); // 找到后停止观察
}
}
});

observer.observe(document.body, {
childList: true,
subtree: true,
});
})();

3. 开始使用

完成以上步骤后,打开任意一篇有道云笔记的分享链接。你会发现页面右下角出现了一个绿色的“导出为 MD”按钮。点击它,当前笔记就会被自动转换为 .md 文件并下载到本地。

导出按钮示意图

方法二:使用 Python 脚本(批量、完整备份)

当你需要导出大量笔记,或者希望进行一次完整的本地备份时,使用由 Github 里其他大佬编写的 Python 脚本会是更高效的选择

1. 准备环境并下载项目

首先,确保你的电脑上安装了 GitPython 3

然后,打开命令行工具(如 Terminal 或 PowerShell),克隆项目代码:

1
2
git clone https://github.com/chunxingque/youdaonote-pull.git
cd youdaonote-pull

2. 安装项目依赖

进入项目目录后,使用 pip 安装所需的依赖库。

Windows:

1
pip install -r requirements.txt

macOS / Linux:

1
pip3 install -r requirements.txt

提示:建议使用虚拟环境(如 venv)来管理项目依赖,以避免与系统全局环境冲突。

3. 配置登录 Cookies

由于有道云笔记的登录机制更新,该脚本目前不支持账号密码登录,需要通过配置 Cookies 来获取访问权限。

获取 Cookies 的便捷方法:

手动在开发者工具中寻找 Cookies 字段既繁琐又容易出错。你可以使用以下 JavaScript 脚本快速生成所需的 JSON 配置。

  1. 在浏览器中登录你的有道云笔记网页版。

  2. F12 打开开发者工具,切换到 Network (网络) 标签页。

  3. 刷新页面,找到一个主请求(通常是第一个),在 Headers (标头) 下找到 Request Headers (请求标头) 中的 Cookie 字段,并复制其完整的字符串值
    image-20250926203712856

  4. 切换到 Console (控制台) 标签页,粘贴以下代码,并将 '这里把上图Cookie属性的值丢进来' 替换为你刚刚复制的字符串,然后按回车

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var tmp_cookie = "这里把上图Cookie属性的值丢进来";

function getCookies() {
var cookies = tmp_cookie.split(";");
var result = [];
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
var parts = cookie.split("=");
var name = parts[0];
var value = parts[1];
if (
name === "YNOTE_CSTK" ||
name === "YNOTE_LOGIN" ||
name === "YNOTE_SESS"
) {
result.push([name, value, ".note.youdao.com", "/"]);
}
}
return result;
}

var formattedCookies = { cookies: getCookies() };
console.warn(JSON.stringify(formattedCookies, null, 2));
  1. 控制台会输出一段格式化好的 JSON 内容。将其完整复制
  2. 在项目根目录下创建一个名为 cookies.json 的文件,并将复制的内容粘贴进去

4. 配置脚本参数

在项目根目录下,找到并编辑 config.json 文件,根据你的需求进行设置

1
2
3
4
5
6
7
8
{
"local_dir": "",
"ydnote_dir": "",
"smms_secret_token": "",
"is_relative_path": true,
"del_spare_file": false,
"del_spare_dir": false
}
  • local_dir: 本地存储目录。选填,导出的笔记将存放在这里,不填则默认为当前项目文件夹。
  • ydnote_dir: 有道云笔记目录。选填,指定要导出的云端文件夹路径,如 根目录/子目录。不填则默认导出所有笔记。
  • smms_secret_token: SM.MS 图床 Token。选填,用于将笔记中的图片上传到 SM.MS 图床。不填则图片会下载到本地。
  • is_relative_path: 图片/附件路径。默认为 true,在 Markdown 文件中使用相对路径引用本地图片和附件。
  • del_spare_file: 删除多余文件。设为 true 时,脚本会删除本地存在但云端已删除的文件。
  • del_spare_dir: 删除多余目录。设为 true 时,脚本会删除本地存在但云端已删除的目录。

注意del_spare_filedel_spare_dir 是为了同步本地与云端的状态。建议先开启 del_spare_file 自动清理,目录则根据情况手动清理

5. 执行导出与后续更新

首次运行

配置完成后,在命令行中运行脚本:

1
2
3
4
5
# Windows
python pull_notes.py

# macOS / Linux
python3 pull_notes.py

脚本将开始拉取并转换你的笔记。如果遇到某个笔记拉取失败,可能是其格式较旧,可以尝试在有道云中新建一篇笔记,将旧内容复制过去再重新运行脚本

后续更新

再次运行相同的命令即可。脚本会根据文件的最后修改时间智能判断,只更新那些在云端被修改过或新增的笔记,不会覆盖你在本地修改过的文件

重要提示:请避免同时在有道云和本地修改同一篇笔记,这可能导致本地的修改在同步时被覆盖丢失

总结

本文介绍了两种将有道云笔记导出为 Markdown 的方法:

  • 油猴脚本:轻量、便捷,非常适合即时导出单篇文章
  • Python 脚本:强大、全面,是进行批量迁移和完整备份的不二之选

根据你的具体需求,选择合适的方法,即可轻松地将你的知识库掌握在自己手中