安卓手机导出短信并解析

因为工作原因,这几年短信量激增,短信量已经增加到14万多条。手机是华为的mate 40 pro,没有升级鸿蒙,仍然是EMUI系统,最后一个版本。
我的需求很简单,短信太多了,系统自带的短信应用,已经不能搜索了,输入后就搜索不出来了。在网上找了一些方案,使用华为套件来看看。
使用华为套件,点击到通讯录是可以正常工作的,也能导出内容,但是当点击到短信的时候,就卡死了,不知道是程序哪里的bug,打华为客服,前后沟通了一个多星期,也是无果,后来就没管了。
使用华为备份产生的文件,需要解密,然后再查找短信,但网上找到的解密渠道也失效了,无法解密。

简单的需求

手机短信太多了,无法搜索,想将手机短信存档,对于历史短信,有需要时能快速搜索即可。

近期的方案

  • SMS Backup & Restore 备份短信,备份出来的xml文件。去google play商店或者apkure商店下载即可。
  • 文件解析并导入到mongodb,使用compass进行查询。

短信导出

推荐方法

  1. 打开,sms backup & Restore,以英文界面为例, settings – Backup location ->Local backup folder 选择一个你熟悉的目录,最好是短目录,不然后面使用adb 的时候,不好拉出文件,当然你也可以通过其他方法把导出的文件备份出来。
  2. 这里我是将文件存储到Downloads目录中,后面的文件名,你看一下填写对应备份出来的文件即可。adb是连接了电脑,你可以把这个文件复制到指定的目录。
adb pull /storage/emulated/0/Download/sms-20241204152305.xml ./sms-backup-20241204.xml

注意点:注意导出设置的时候,允许读取通讯录,这样你可以看到有一个字段,contact_name,短信的易读性会好很多。

另一种导出的办法

使用 Content Provider 导出短信 Android 提供了一种标准方法,通过 content:// URI 来访问短信数据:

adb shell content query --uri content://sms > sms_data.txt

这个会在当前目录下生成一个sms_data.txt的目录。

两种方法比较

Content Provider导出:导出的是广本行,没有解析,以=分隔,如果数据中有=号会造成后续分隔困难。
Sms Backup & Restore: 导出的xml格式,可以直接解析,方便导入到json中。

解析xml数据并导入到mongodb中

解析思路

  1. 有唯一主键,这样后续再导入的时候,因为备份都是全量备份,后续随便导入,但有主键后,重复的将数据将不会被再插入到数据库中。使用了address,date,type,body,sub_id进行组合生成md5的hash值作为数据库的_id。
  2. 解析字段完成后,利用python的list完成插入。

相关代码

import xml.etree.ElementTree as ET  
import json  
from pymongo import MongoClient  
import hashlib  

def generate_unique_id(sms):  
    unique_string = f"{sms['address']}_{sms['date']}_{sms['type']}_{sms.get('body', '')}_{sms.get('sub_id', '')}"  
    return hashlib.md5(unique_string.encode()).hexdigest()  

# 解析 XML  
tree = ET.parse('data/sms-backup-20241204.xml')  
root = tree.getroot()  

sms_list = []  
for sms in root.findall('sms'):  
    sms_list.append({  
        'address': sms.get('address'),  
        'date': sms.get('date'),  
        'type': sms.get('type'),  
        'contact_name' : sms.get('contact_name'),  
        'body': sms.get('body'),  
         'sub_id': sms.get('sub_id'),  
        'read': sms.get('read'),  
        'status':sms.get('status'),  
        'date_sent': sms.get('date_sent')  
    })  

# 保存为 JSON 文件  
with open('data/sms_data.json', 'w', encoding='utf-8') as f:  
    json.dump(sms_list, f, ensure_ascii=False, indent=4)  

## add primary key  
for sms in sms_list:  
    sms["_id"] = generate_unique_id(sms)  

# 导入到 MongoDB  

USERNAME = "admin"  
PASSWORD = "test1234"  
HOST = "10.0.1.21"  # 或远程服务器地址  
PORT = 27017        # MongoDB 默认端口  
DATABASE = "sms"  
COLLECTION = "sms_collection"  
# 连接 MongoDB  
client = MongoClient(f"mongodb://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/")  
db = client[DATABASE]  
collection = db[COLLECTION]  

try:  
    collection.insert_many(sms_list, ordered=False)  # 跳过重复记录  
    print("短信数据已成功导入 MongoDB!")  
except Exception as e:  
    print(f"导入时出现错误:{e}")

xml导出的字段说明

  • protocol 协议类型,通常为 0,表示标准 SMS 协议
  • address 短信的发送方或接收方号码
  • date 短信发送或接收的时间戳(1970 年 1 月 1 日以来的毫秒数)
  • type 短信类型:1 表示接收,2 表示发送
  • subject 短信主题,通常为 null,适用于 MMS 或其他多媒体消息
  • body 短信内容
  • toa 接收方号码地址,通常为 null
  • sc_toa 短信服务中心地址,通常为 null
  • service_center 短信的服务中心信息,通常为 null
  • read 短信是否已读:1 表示已读,0 表示未读
  • status 短信状态:-1 表示无特殊状态;其他值可能表示发送失败等状态
  • locked 短信是否被锁定:1 表示锁定,0 表示未锁定
  • date_sent 短信的实际发送时间(1970 年 1 月 1 日以来的毫秒数)
  • sub_id 订阅卡 ID(双卡手机时标记 SIM 卡)
  • readable_date 人类可读的时间格式(如 Oct 28, 2015 19:57:25)
  • contact_name 联系人名称,若未知则为 (Unknown)

查询示例

mongodb操作

创建索引

db.sms_collection.createIndex({body: "text"});

查找特定文字

db.sms_collection.findOne({body: /游多多/i});

查询截图

这还能查到好多年前的短信,15年的。

1af609529e756da2b1d103db721b8ce3.png

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇