作者:DeppWang
開發了個 《一鍵導出 / 備份「有道雲筆記」所有筆記》的腳本。主要原理是利用有道雲筆記本身的接口。下面是根據正常用戶操作邏輯,找到需要的接口,主要是登錄和「下載」。
一、登錄
登錄的目的是獲取 Cookie
1.1 找登錄接口
接口應該在登錄時執行。使用錯誤密碼測試,可得到登錄 post 請求接口。注意過濾條件是 All
https://note.youdao.com/login/acc/urs/verify/check?app=web&product=YNOTE&tp=urstoken&cf=6&fr=1&systemName=&deviceType=&ru=
https://note.youdao.com/signIn//loginCallback.html&er=
https://note.youdao.com/signIn//loginCallback.html&
vcode=dman9&systemName=mac&deviceType=MacPC×tamp=1591770253472
1.2 推導密碼加密規則
本地測試使用同樣錯誤密碼用不同加密算法加密,看加密結果是否一致
發現使用 md5 加密
## Python
password=hashlib.md5(password.encode('utf-8')).hexdigest()
1.3 找返回驗證登錄狀態 Cookie 的接口
登錄成功後,會返回驗證登錄狀態的 Cookie。接口應該在登錄成功後執行。發現跳轉首頁後第一個 XHR 接口中包含驗證登錄狀態的 Cookie,YNOTE_CSTK
https://note.youdao.com/yws/mapi/user?method=get&multilevelEnable=true
二、「下載」
2.1 找返回根目錄 id 的接口
我們根據一個筆記 URL 可以看出,URL 裏包含了父文件夾 id 和當前文件 id。「我的文件夾」下的 test.md 的 URL:
https://note.youdao.com/web/#/file/F83DF1ADA69344D194C7CE861D09B1A1/note/WEB4aa8bf8074d61befea1dd20f5593f01c/
「我的文件夾」 是根目錄,它的 id 是 F83DF1ADA69344D194C7CE861D09B1A1
,下面稱它爲 root_id。
我們推測,有道雲筆記是設計是根據文件夾 id,獲取文件夾下的所有文件信息(打開文件夾,可看到文件夾下的文件)。所以我們需要先得到 root_id。當登錄成功後,跳轉到首頁時,應該有接口能得到 root_id。
測試發現下面接口返回值包含 root_id:
https://note.youdao.com/yws/api/personal/file?method=getByPath&keyfrom=web&cstk=01PvSwwu
接口返回格式類似這樣:
{
"fileEntry":{
"userId":"[email protected]",
"id":"F83DF1ADA69344D194C7CE861D09B1A1", // root_id
"version":22888,
"name":"ROOT",
"parentId":"0",
"createTimeForSort":1497860357,
"modifyTimeForSort":1497860357,
....
},
"fileMeta":{
"chunkList":"None",
"sharedCount":0,
"title":"ROOT",
...
},
...
}
root_id = response.content['fileEntry']['id']
2.2 找獲取目錄下所有文件信息的接口
有了 root_id,需要找到根據 id 獲取目錄下所有文件信息的接口。
接口應該在打開文件夾時執行。點擊某一個文件夾,測試發現包含當前目錄所有文件信息的接口爲:
https://note.youdao.com/yws/api/personal/file/9d8a2385eeec77338211b4f04bbf844d?all=true&f=true&len=30&sort=1&isReverse=false&method=listPageByParentId&keyfrom=web&cstk=01PvSwwu
接口返回格式跟上面差不多,只是數量更多,屬性多了 parentId(父文件夾 id)。
[
{
"fileEntry":{
"userId":"[email protected]",
"id":"9d8a2385eeec77338211b4f04bbf844d",
"version":14168,
"name":"來自手機",
"parentId":"F83DF1ADA69344D194C7CE861D09B1A1", // 父文件夾的 id,此時是 root_id
"createTimeForSort":1550712995,
"modifyTimeForSort":1550713003,
....
},
"fileMeta":{
"chunkList":null,
"sharedCount":0,
"title":"來自手機",
"fileSize":0,
...
},
...
}
...
]
2.3 找到獲取文件內容的接口
通過文件夾 id 得到了文件 id(fileId),需要找到根據 fileId 獲取文件內容的接口。
接口應該在點擊筆記標題得到筆記內容時執行。點擊某一篇筆記標題,可以找到獲取文件內容的接口:
https://note.youdao.com/yws/api/personal/sync?method=download&keyfrom=web&cstk=01PvSwwu
三、模擬瀏覽器操作
3.1 設置請求頭
隨便哪個頁面(如:首頁 https://note.youdao.com/
)可以看到請求頭包含下面這些內容:
取一部分設置即可
class YoudaoNoteSession(requests.Session):
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36',
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
}
3.2 模擬「進入網頁版」
self.get('https://note.youdao.com/web/')
點擊「進入網頁版」,會重定向到登錄頁面
3.3 模擬打開登錄頁
self.get('https://note.youdao.com/signIn/index.html?&callback=https%3A%2F%2Fnote.youdao.com%2Fweb%2F&from=web')
跳轉登錄頁後,要執行下面 3 個接口:
self.get('https://note.youdao.com/login/acc/pe/getsess?product=YNOTE&_=' + timestamp())
self.get('https://note.youdao.com/auth/cq.json?app=web&_=' + timestamp())
self.get('https://note.youdao.com/auth/urs/login.json?app=web&_=' + timestamp())
四、結語
根據找到的接口,模擬用戶操作也有不少應用場景。除了開發像這種導出文件的腳本,可以開發一切你想自動化執行的操作。比方 cnblogs、juejin 發文章等。比較麻煩的就是像上面這樣找接口了,可以先看看有沒有人有過總結。
也可以利用一些瀏覽器的 API,如 Puppeteer,它提供一個真實的瀏覽器環境,可以真正模擬用戶操作,不需要找到所有接口,只需要設置網頁 url,以及設置需要操作的「按鈕」屬性。因爲提供瀏覽器環境,它屬於重量級操作。可以看看 ArtiPub 如何使用 Puppeteer。這種方式有點不好的地方就是平臺可能改前端屬性,需要注意更新。
全文完。