一个Python脚本是怎么备份整库有道云笔记的?youdaonote-pull原理解码
【免费下载链接】youdaonote-pull📝 一个一键导出 / 备份「有道云笔记」所有笔记的 Python 脚本。 A Python script to export/backup all the notes of the "Youdao Note".项目地址: https://gitcode.com/gh_mirrors/yo/youdaonote-pull
youdaonote-pull 是一个能一键导出、备份有道云笔记全部笔记的 Python 脚本,下载到的专有格式笔记会被自动转成 Markdown,图片和附件一并落到本地,重复运行时只增量下载。脚本全程在本地运行,数据不出你自己的电脑。
你可能也遇到过这个糟心事:有道云笔记的网页版和客户端早就撤掉了「导出全部笔记」的入口,你却想把几年的笔记搬进本地 Markdown 编辑器,搬不动。作者一开始想走官方 API,结果发现 API 多年没更新,连 Markdown 接口都没有,最后换了条路:借用网页版在用的同一批接口,模拟浏览器请求把笔记一条条拉下来。整件事拆开来就四步——进门、走目录、洗格式、修图。
🔑 登录态从哪来:脚本怎么不用密码就登进去
有道云早就不让账号密码登录了,验证码一拦,这条路走不通。脚本的办法类似门禁卡:你浏览器里已经登过,登录状态就存在 Cookies 里,把三个关键字抄出来放进cookies.json即可。其中YNOTE_CSTK是每次请求都要带的「验证券」,缺了它脚本会直接拒绝启动。
读完文件后,脚本把四元组逐条塞进请求会话:
for cookie in cookies: # 把本地文件里的四元组装进会话 self.session.cookies.set( name=cookie[0], value=cookie[1], domain=cookie[2], path=cookie[3] )登录就这一件事,之后每次请求都自动带着这份状态,你不用再输一次密码。具体实现在 core/api.py 的login_by_cookies方法里。
🗂️ 脚本怎么把整棵云目录树走一遍
登录后的第一动作是问出根目录的「ID」,之后就是一个简单的循环:拿着目录 ID 取它的子项,子项若是文件夹,就在本地建同名目录再钻进去;若是笔记,就下载内容。跟逛公寓的房间一个道理,每进一间记清内容,顺手打开遇到的门。
文件类型是怎么判定的
不是所有文件都要洗。.md文件原样保存,.doc之类的普通文件照搬,只有.note笔记需要转换。可笔记内容本身不统一:老笔记是 XML,新笔记是 JSON。脚本看开头几个字节就能分清:
if response.content[:5] == b"<?xml": file_type = FileType.XML # 老式笔记,XML elif response.content.startswith(b'{"'): file_type = FileType.JSON # 新式笔记,JSON🧩 为什么 .note 文件不能直接读
XML 吐出来的是标签树,不是正文。转换思路是给每种标签配一条「翻译规则」,分发逻辑很简单:把标签名洗干净,再按名字找对应的转换函数:
name = element.tag.replace("{http://note.youdao.com}", "").replace("-", "_") convert_func = getattr(XmlElementConvert, "convert_{}_func".format(name), None)比如标题标签heading level="2"会变成## 标题;代码块标签带着language子标签,直接套上三反引号;待办事项变成- [ ]。这些规则都写在 core/covert.py,2017 年以前的老 HTML 笔记则交给markdownify库直接转。
表格转换最容易踩的坑
表格内容是塞在 XML 标签里的一串 JSON 文本,解析完得到的是平铺的单元格列表,行结构丢了,得按列数「攒够一行」再拼回来。容易翻车的是两处:表格只有一行时,要手动补一行标题行和分隔行,否则 Markdown 渲染器不认账;单元格里的文字要把星号、下划线转义,换行换成<br>,不然一个单元格就能把整张表撑破。
为什么笔记里的图导出后全是「裂图」
有道图床只认登录态,导出的 Markdown 里图片链接基本必裂。脚本的做法像一队救图工:正则把正文里所有note.youdao.com链接挑出来,逐个下载,存进笔记同级的images/文件夹,再把链接改写成本地路径。若在config.json里填了smms_secret_token,图片会先传 SM.MS 图床、md 里留在线地址;上传撞限额或失败时自动退回本地下载,不会卡死在半路。想拿 Obsidian 打开就把is_relative_path设为true,链接会保留成相对路径。整个过程都在 core/image.py 的migration_ydnote_url里。
⏱️ 第二次运行,为什么已下载的不重拉
每次全量重拉太慢,脚本用了「比对时间戳」的土办法:云端每个文件都有修改时间,本地文件时间更新就跳过。细节也讲究——下载成功后,把云端笔记的修改时间回写到本地文件(用os.utime,Windows 需要win32-setctime库),下次比较才一直有效。要记一个坑:云端和本地别同时改同一个文件,本地修改可能被覆盖。
最后落地的文件夹长什么样
跑完默认生成脚本同级的youdaonote文件夹(用config.json的local_dir改),结构跟云端一致:子文件夹是子文件夹,笔记已改名成.md,图片在images/,附件在attachments/。不想真登录测试的话,可以先看test/目录里的样例:test.note和test.json是两份真实原始笔记,test.md和test-json.md是对应的转换结果,对着比一比就能看出洗稿效果。
动手的话,先git clone https://gitcode.com/gh_mirrors/yo/youdaonote-pull,填好cookies.json和config.json两个文件,再跑python3 pull.py。日志会告诉你哪些文件「新增」、哪些「跳过」,最后一行报耗时。遇到 Cookies 过期或接口变动,先跑一遍 test/test.py 的测试用例自查,确认有问题再去提 issue。整套代码就几百行,值得从头到尾读一遍。
【免费下载链接】youdaonote-pull📝 一个一键导出 / 备份「有道云笔记」所有笔记的 Python 脚本。 A Python script to export/backup all the notes of the "Youdao Note".项目地址: https://gitcode.com/gh_mirrors/yo/youdaonote-pull
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考