ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

一键备份有道云笔记到 Markdown:youdaonote-pull 是怎么造出来的

一键备份有道云笔记到 Markdown:youdaonote-pull 是怎么造出来的 一键备份有道云笔记到 Markdownyoudaonote-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你存了五年笔记的有道云笔记突然想整体搬到 Obsidian 或 Typora却发现网页端早已悄悄收掉了「导出所有笔记」的按钮——单条笔记只能右键保存几百条笔记根本无从下手。youdaonote-pull 就是为这个场景做的一个完全本地运行的 Python 脚本登录一次你的云笔记把整棵目录树原样拉到硬盘上笔记自动转成 Markdown连笔记里的图片也一并搬到本地。这篇文章写给想搞懂它到底怎么实现的的 Python 初学者不堆 API 文档只讲一条笔记从云端到磁盘的完整旅程以及作者在关键岔路口做的三个选择。先拿一张地图一条笔记的完整旅程整个工具不到 1000 行有效代码分四层pull.py 是总调度负责配置校验、目录遍历和增量判断core/api.py 只干一件事——用requests会话伪装成浏览器调用有道云笔记的 3 个网页接口core/covert.py 把专有的 XML / JSON 笔记体翻译成 Markdowncore/image.py 负责把笔记正文里的图片、附件链接搬到本地。一条笔记的完整流向是这样的浏览器登录产生的 Cookies │ ▼ cookies.json ──► YoudaoNoteApi 会话3 个接口根目录 / 目录列表 / 文件下载 │ ▼ 递归遍历目录树 云端 .note / .clip 文件 ──► 先按原样落盘.note │ ▼ 按文件头嗅探格式 XML ──► 元素规则映射 ──► Markdown.md JSON ─► 编号字段解析 ──► Markdown.md HTML2017 年前的老笔记──► markdownify 兜底 │ ▼ 图片/附件链接 ──► 下载到 images / attachments 文件夹 ──► 正文链接改写 │ ▼ 本地文件时间戳 云端创建/修改时间供下次增量同步比对记住这条链路下面每一步都是它的展开。跟着一条笔记跑完全程第一步不带密码的登录最直觉的做法是脚本里内置账号密码登录但有道早已给登录流程加上图形验证码纯脚本很难稳定过验证。作者换了个思路人在浏览器里正常登录一次然后把会话凭据Cookies复制出来存成cookies.json脚本启动时把这些 Cookie 灌进requests.Session之后每个请求都自动带上。它解决的本质问题是绕过验证码复用你已经完成的登录态同时凭据只留在你本机。登录态里最特别的是YNOTE_CSTK这个 Cookie——有道的反爬校验参数。每个接口的 URL 和请求体里都要带上它脚本在登录时把它单独抠出来后面所有请求统一注入self.cstk ( cookies[0][1] if cookies[0][0] YNOTE_CSTK else None )另外core/api.py 里还写了一整套 Chrome 的User-Agent和sec-ch-ua请求头目的都是让服务器把脚本当成一个正常的网页浏览器而不是某个来路不明的爬虫。第二步拿到目录 ID递归走树登录成功后脚本先用getByPath接口问出根目录的 ID然后进入一个递归函数给定一个目录 ID调listPageByParentId接口拿它下面所有条目一次最多 1000 条是文件夹就建本地同名子目录再递归下去是文件就交给下一步处理for entry in entries: if file_entry[dir]: os.mkdir(sub_dir) self.pull_dir_by_id_recursively(id, sub_dir) # 子目录递归 else: self._add_or_update_file(id, name, local_dir, modify_time, create_time)这段代码解决的是云端树状结构与本地文件系统的一一映射——你在有道里建的文件夹层级在硬盘上会被完整复刻。第三步增量判断别每次都全量下载每个云端条目都带着modifyTimeForSort最后修改时间戳。脚本拿它和本地同名文件的修改时间一比就能得出三种动作之一本地没有 →新增必须下载云端时间 ≤ 本地时间 →跳过说明你本地可能改过云端是旧的云端时间 本地时间 →更新重新下载覆盖这是整套工具里最聪明的一处细节文件下载完成后脚本会立刻用os.utime把本地文件的修改时间强行改回云端的修改时间Windows 下还要借助win32-setctime补上创建时间。时间戳被回写校准后下一次运行比对的锚点就永远不会漂移增量同步才能真正成立。第四步先落原文件再嗅探、再翻译拿到文件字节后脚本并不急着转换而是先按原后缀.note/.clip把原始内容写进硬盘。这步看似多余却是后面所有容错策略的地基。接着做格式嗅探规则朴素得可爱.md文件原样保留.note文件看前 5 个字节是不是?xml是则按 XML 处理开头是{的按 JSON 处理。XML 和 JSON 是同一批笔记在不同时期的两种存储格式core/covert.py 里因此有两套并行的转换规则。XML 转换没有用复杂的转换库而是手工建了一张元素 → 函数的映射表每个笔记元素类型标题、段落、代码块、引用、待办、表格……对应一个静态方法。标题按level属性拼成#数量代码块包上 和语言名表格的单元格数据本身是一段 JSON要再解析一次才能拼出 Markdown 表格。每个方法都短小加一种新元素只需再加一个方法。第五步把图片从有道的图床上搬下来转好的 Markdown 里图片还是note.youdao.com的链接——这些链接带着登录态校验离开有道环境就是死链。core/image.py 用两条正则分别找出正文里的图片链接和附件链接逐个下载图片存到笔记同级的images/文件夹附件存到attachments/文件夹然后把正文里的链接原地替换成本地路径。如果配置了 SM.MS 图床 Token就改成上传到第三方图床拿外链免费版限速每分钟 20 张、每小时 100 张超限自动退回本地方案。默认还开着相对路径模式——把images/xxx.png这种以images开头的相对路径写进正文Obsidian 这类笔记库能直接识别。第六步一条链式兜底专治老笔记最后一步藏着作者踩坑的痕迹。老笔记大约 2017 年以前根本不是 XML而是 HTML。如果只写 XML 解析这批笔记全会报错。于是转换入口做成了三级回退XML 解析失败 → 当 HTML 交给markdownify转 → 再失败 → 打日志跳过保留原始文件不删。配合先落原文件再翻译的策略最坏情况下你损失的只是格式数据本身永远不会丢。三个值得琢磨的设计决策决策一Cookies 登录 vs 账号密码登录本可以这么做逆向有道的登录接口用账号密码 验证码识别自动化登录体验上确实更一键。最后选了 Cookies用户在浏览器里正常过完验证码把三个 CookieYNOTE_CSTK、YNOTE_LOGIN、YNOTE_SESS粘进cookies.json即可。权衡很现实——验证码识别是个无底洞接口随时会变而 Cookies 方案把最难的部分交还给浏览器脚本只负责拿着通行证进门。代价是 Cookie 会过期需要偶尔重新复制这个成本远小于维护一套打码逻辑。决策二增量同步的比对锚点选在修改时间本可以这么做每次全量下载覆盖本地逻辑最简单永远不会漏。最后选了基于修改时间的增量第一次全量之后只拉新增和变过的笔记并且绝不覆盖本地时间更新的同名文件。对动辄上千篇、几 GB 图片的笔记库全量重拉的流量和时间都不可接受。作者为此做了两件配套的事下载后回写校准本地时间戳否则第二次运行就会全量重判以及一条明确的边界提醒——云端和本地同时改同一个文件时本地修改会丢增量同步本质上是单向的。决策三转换失败不抛异常而是降级本可以这么做把 XML → Markdown 写成一条严格流水线遇到未知结构直接报错。最后选了先保数据、再谈格式原始文件永远先落盘格式嗅探只认文件头不认识的后缀直接原样保存转换入口带 HTML 兜底甚至单张图片下载失败也只记日志、继续处理下一张。整个 pull.py 的主循环里任何单个文件出错都不会让整次备份崩掉——因为备份工具的第一原则是跑完了就都安全了优雅报错排在第二。跑起来然后接着改最简上手需要 Python 3 Gitgit clone https://gitcode.com/gh_mirrors/yo/youdaonote-pull cd youdaonote-pull pip install -r requirements.txt接着做两件事把浏览器里的登录 Cookie 写进cookies.json参考 README.md 里的格式说明在 config.json 里填local_dir导出到哪个文件夹。然后运行python pull.py几分钟后你收获的是一棵和云端同构的目录树、一堆.md文件以及同级images/文件夹里的全部图片。想验证转换逻辑是否正确不需要登录任何账号直接python test/test.py——test/ 目录里放了test.noteXML 原件、test.md期望产物、test.json/test-json.md一对样例测试会逐字节比对转换结果还顺带演示了如何用 mock 替换网络请求做单元测试。两个可以接着做的方向补齐 push做成双向同步。项目最初的设计目标本就是 pull push 一对脚本作者调研过有道 Open API因接口过老、缺 Markdown 支持而放弃。如果你能逆向出网页端的保存接口就能实现本地 Typora 编辑 → 一键推回云端 → 手机上继续看这是这个仓库最有价值的未完成拼图。给转换器加一个输出目标。XmlElementConvert的元素 → 函数映射结构对扩展很友好照着现有方法仿写一套比如输出 HTML 或导入语雀/Notion 的格式新增一个 Convert 类即可不用动主流程一行代码。能带走的三件事网站几乎都有可复用的网页接口。打开浏览器 DevTools 看网络请求把前端渲染换成存到本地就能造出一个专属备份工具——认证走 Cookies、请求头伪装成浏览器、带对反爬参数三板斧够用大半场景。对陌生格式做先嗅探、再分发、后降级。按文件头前几个字节判断真实类型分派给不同解析器解析失败逐级回退并保留原文件。数据完整性永远排在格式美观之前。增量同步的灵魂是锚点校准。光会比较修改时间不够落盘后还得把本地时间戳回写成远端时间比对锚点才不会漂移——这个一行os.utime的细节决定了第二次运行是秒级跳过还是几 GB 重下。【免费下载链接】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),仅供参考
返回列表