有道云笔记数据导出

0x00 引言

      首先,为什么要干这么蛋疼的事呢?我也很无奈啊.

      从2011年开始使用云笔记,那会带云同步的笔记还不多,主要就是evernote(印象笔记,大象),有道和为知(wiz),用了一段时间大象,每月几十兆,客户端庞大,然后试用了有道和wiz,当年也不知道为什么会选择有道而不是wiz,可能有一部分原因,有道和大象之间相互迁移很方便吧,然而多年后的今天,啪啪打脸.

      要说网易吧,真是有能力好好做产品,偏要干点跌档次的事情.有道词典当年做的多好,非要插一大堆广告,弄的越来越臃肿,现在勉强电脑用用,手机上用欧陆,但是词典源首选的是有道,谁让有道有柯林斯的资源呢.网易邮箱也是广为使用,但是用网易发邮件,邮件末尾非要附上点小广告(我从来不用126,163,但收到的个人发给我的邮件最下面有小广告,也是蛮迷的).网易云笔记也是,PC上的界面做的很不原生,没有win应用的设计感,后来加了云协作,后台一个YNoteCefRender.exe的进程疯狂吃CPU,亏得是单线程,我4核(准确是四逻辑内核)的U被这一个进程常规占用20%左右,要是4线程的,我这电脑就别用了,而且这个问题大半年前就有人反应了,有道官方也回复了,结果半年多过去都没有解决,不是搞笑呢吗.云协作感觉应该就是在PC应用里直接把网页版的云协作嵌入进来就OK了,一点也不正义,也难怪会出这种问题.此外迁入迁出功能受到极大限制,不能导出为大象的文件或其他通用类型的文件了,想靠这种封闭出口的方法留住用户,真的是很naive.

     吐槽完毕,下面进入正文.

PREREQUISITIES:
- 有道云笔记5.6.0.0
- WinHex
- Anaconda 2.7 ( Python 2.7 )

0x01 准备工作

     首先将有道云协作中需要备份的笔记保存到云笔记中,保存完毕后应该会在笔记本'我的资源'中看到一个新的笔记本'来自云协作',该笔记本内包含了从云协作保存到云笔记的笔记.

     然后需要获得云笔记的备份文件.选择右上角倒数第四个图标 --> 导出 --> 有道云笔记 文件,得到所有笔记的备份文件,后缀名应该为.ynt(有道云笔记3.x导出的好像是.ynote格式,这两种是不一样的).该备份文件包含了所有的笔记内容和笔记中的文件和附件.

     获得了所有个人笔记的.ynt备份文件后,用压缩软件打开该文件,解压后,得到一个文件夹.文件夹包含一个Note文件夹,Note文件夹内一个子目录的树状结构大约如下所示:

├─B9A878F3963D404B95BDAEA2DFA964F (笔记文件夹)
│ │ Content (笔记内容)
│ │ Info (笔记标题)
│ │
│ └─Resources
│ ├─52A96111A6D949CAB2B85B9C00B3DA6 (附件所在文件夹)
│ │ Content (附件内容)
│ │ Info (附件引用名称和文件名)
│ │
│ └─D8F40AEFEA9D4FAD9D4A4291AB655F5
│ Content
│ Info
... ... ... ...

     首先Note的子文件夹对应一个笔记,其中Info存储了笔记的标题,以及链接(详细信息--来源),获取标题基本足够了;Content文件存储了笔记的内容,解析出来是html格式的;笔记的附件,包括笔记中的图片,保存的pdf,office文档,压缩包,exe或其他类型的文件等,其Info文件中存储了长度为32的一串字符(后文就称作附件散列吧),在笔记内容中通过这长度32的字串(附件散列),来引用相应的文件,Content是未修改的附件原文件,如果知道附件类型,比如是jpg图片,那直接把Content文件重命名为Content.jpg就可以用看图软件打开看到图片了,其他格式同理.这里需要注意一下,附件所在的文件夹的名字(长度32的字串)和附件散列是不一样的.

     以上获得了所有的笔记,不过缺失了笔记本的结构特征(即笔记是存在哪个文件夹里的,文件夹之间又是什么样的层级关系).按照道理,备份文件中应该会存储笔记本结构的,不过我并没有找到.这里有一个替代方案,就是可以在安卓版的有道云笔记的数据中找到sqlite的数据库文件,里面存储了所有笔记本名称,上级目录和子目录,可以恢复所有笔记的存储结构.

     首先需要一台拥有root权限的安卓机,安装好有道云笔记,登陆账号,同步后.用Root Explorer(或其他什么文件浏览器)进入到/data/user/0/com.youdao.note.找到文件夹databases,会发现一个几兆左右(视笔记的多少而定)以用户邮箱命名的db文件,将这个数据库文件拷贝到电脑,用sqlite browser或其他什么sqlite数据库的浏览器打开,可以看到里面存了很多表.note_meta表中存储了所有的笔记的标题,摘要,所属笔记本等信息;note_books表中存储了所有笔记本的id,标题,笔记数目,所属笔记本等信息;resource_meta表存储了所有附件的id(附件散列),文件名,文件长度等信息;group_开头的表都是和云协作有关的.通过以上信息就可以确定笔记和笔记本的组织结构,不过鉴于我暂时没有这个需求,就没有实现这个功能.

0x02 编码解析与数据分析

     了解了云笔记的备份文件的目录结构,下一步就是要把每个文件中的内容解析出来.用Notepad++等编辑器打开Info或Content文件时会看到一堆乱码,不可卒读.这是因为不知道文件的编码,没法显示正确的内容.

     经过我的尝试与分析,备份中的文件主要编码是用的UTF-16(吐槽:好好的UTF-8不用,也够蛋疼的,估计就是怕用户太容易发现).

     使用WinHex解析某附件的Info文件,得到以下的内容:

分析得到以下特征:

  • 前4个字节是无意义的,可以直接忽略.
  • 0x04到0x43这64字节是文件散列(含义见0x01),由于采用UTF-16,每个字符2个字节,所以这是一个长度32的字串
  • 0x64之后是附件的文件名,分隔符每个Info文件不尽相同
  • 最后一段也是附件文件名,没有理解为什么要放两个相同的文件名,分隔符也是每个Info文件不尽相同

     至于Content的内容,由于不需分割,对于笔记内容,直接解码后保存;对于附件文件,直接重命名保存;不再赘述.

     具体如何操作见代码吧.毕竟古语有云:'Talk is cheap, show me the code!'


https://github.com/elitezhe/ynotebackparsing

0x03 生成HTML笔记

     有了前面的基础,这一步其实已经非常简单了.

     这里需要生成的笔记HTML文件,不需要具有完整的HTML结构,也就是说head,body这些标签统统不要,也能玩,偷懒起见,我就这么干了.

     直接把Content解析出来的笔记内容保存到文件中,文件标题保存为笔记的标题.然后把相应的附件重命名为文件散列,复制到HTML文件相同的目录下即可.

     具体操作和细节同样是见代码.

0x04 将HTML笔记导入wiz笔记

     wiz笔记提供了导入HTML的功能,不幸的是附件只能导入图片类型的文件,至于pdf,office等其他类型的文件统统歇菜.也查了一些资料,目前wiz似乎并没有开放文件导入的API,也就懒得想点什么奇技淫巧(比如按键精灵,,手动滑稽)来实现文件导入功能了.对于这个问题也有一个解决方法,有道云笔记导出功能里有一个全部导出为本地数据,会把所有附件保存出来,文件名也是正常的.真需要附件的话,可以在笔记中看到附件的文件名,然后到导出的附件目录里搜一下这个文件名也能找到..就是不那么优雅了.

0x05 一些仍然存在的小问题

  • 云笔记导出的笔记中会有很多奇怪的字符串填充在其间,很是蛋疼
  • 由于生产HTML时,没有额外的信息,直接用浏览器打开会不识别编码,导致显示的是乱码,只要在浏览器手动调一下编码为UTF-8就正常了
  • 可能由于类似上面的原因,导入wiz时,可能有部分笔记存在导入成乱码,对于我本人的笔记,有一两条出现这种问题,数量不多,手动处理下算了