短信不算笔记,但同样是散在外面的一份记录。既然要把这些东西收敛到本地,便签之外顺手把它也拿下来。脚本在 GitHub 上:phone-cloud-data-export/flyme-sms。
魅族云的短信备份页面还在,地址 cloud.flyme.cn/browser/sms-list.jsp。我账号里 1595 个会话、7600 条消息,最早一条是 2007 年,最后一条停在 2022 年初。
网页版没有批量导出,只能一页页翻。这篇和魅族云便签、锤子便签是同一批,都用浏览器里跑脚本的办法把数据拿下来,再在本地转成 CSV 和 Markdown。
1. 接口
短信页面的接口都是 POST,表单参数,URL 上要带 tkscsrf:
- 会话列表:
/c/browser/sms/getsmsgroups?tkscsrf=...,body 参数status=phone、type(文件夹)、start、length - 某个会话的消息:
/c/browser/sms/getsmsdialogs?tkscsrf=...,body 参数contact、status=phone、type、start、length
tkscsrf 是页面自己请求里带的令牌,脚本从 performance 里最近一条请求的 URL 上取,取不到再读 Cookie。
抓取脚本按文件夹逐个抓会话,再逐个抓会话里的消息,每页 50 条,同时开 3 个会话,每个请求之间留 90 毫秒。跑的时候标签页要留在前台,后台标签页的定时器会被浏览器降速,慢很多。
每 200 个会话自动存一份分段文件,最后再存一份 full 文件。分段文件是累积快照,中断了重跑不会丢已经抓到的部分。
2. 抓下来的比实际多
接口的 type 参数有 0 到 5 六种取值,实测 type=0/2/4/5 返回的是同一批会话,号码集合和消息都一致,type=3 才是另一批。
抓的时候按 type 和号码两个键记录,所以原始记录数大于实际会话数。输出阶段按号码合并,同一条消息按 uuId 去重,最后是 1595 个会话、7600 条消息。
方向靠接口的 type 字段判断:1 是收件,2 是发件。用几条收发方向明确的短信核对过一致。原始字段都留在 短信原始.json 里,有出入可以回去对。
收 6659 条,发 941 条。收发都有的会话 98 个,只有收的 1455 个,只有发的 42 个。只有收的那批基本都是 106 开头的验证码和通知。
3. 换行
短信正文里混着 \r\n。如果只按 \n 切,行尾会剩一个 \r,在部分编辑器里表现为一个乱码方块。转换脚本先把 \r\n 统一成 \n 再处理。
按联系人的 Markdown 里,每行一条消息,收和发顶格,正文里的换行缩进两格续写:
1 | 收 2014-07-24 04:58:43 晚上一起吃饭吗 |
每行末尾加两个空格当硬换行,否则标准 Markdown 会把整个会话渲染成一整段。这两个空格在代码块里看不出来。加上之后在 Obsidian、VS Code 预览和 GitHub 上都正常换行。风格一样可以换,--line-break=space(默认)、br、blank、keep。
这个账号没有彩信,photo_type 全是 0,所以没有图片要另外下载。
4. 导出结果
输出四个东西:
全部短信.csv:7600 行,一行一条,列是发送时间、方向、对方号码、对方名称、文件夹、正文、uuid。带 BOM,Excel 和 WPS 直接打开不乱码短信原始.json:去重后的完整数据,字段最全,含smsStatus、protocol、photo_type按联系人/*.md:消息数大于等于 2 的 763 个会话,一个会话一个文件,时间正序收发都有/*.md和收发都有.csv:只挑收发都有的 98 个会话
时间范围 2007-11-15 04:40:28 至 2022-01-08 01:10:57。消息最多的一个会话有 684 条。
5. 脚本
都用 node 直接跑,没有第三方依赖:
1 | # CSV + JSON + 导出报告 |
GitHub 仓库:phone-cloud-data-export/flyme-sms