我一直想把自己的微信聊天记录导出来,用来做一些奇奇怪怪的东西。可以用来分析一下过去一年里跟谁聊天了,聊的都是啥,或者做一个带有自己特点的聊天机器人。问题是,微信现在并没有简单导出聊天记录的方法。从我网上搜到的资料,安卓机器上的微信会将聊天记录(还有很多其他数据,比如联系人)保存在一个叫做EnMicroMsg.db的数据库中。这个数据库是使用SQLCipher生成的,没有密码是无法正常打开的。这个密码其实可以很容易通过自己手机的信息以及微信的信息计算出来,我也根据网上的教程计算出属于我的密码了。但是我一直没有成功解密我的聊天记录数据库。直到今天我再次搜寻了关于微信数据库的资料,才发现我不仅仅需要密码,还需要其他一下数据库的设置才能正确打开。这篇博文主要的目的是记录我该怎么做才能导出微信聊天记录,以方便以后使用。

我根据这篇文章从安卓机器中获得自己的聊天记录数据库EnMicroMsg.db并计算属于自己的密码。我的安卓机器已经root了,所以我可以用adb进行如下操作获得微信的uinEnMicroMsg.db

获取uin

adb shell su -c "cat /data/data/com.tencent.mm/shared_prefs/*.xml | grep uin"
    <set name="uin_set">
    <int name="_auth_uin" value="MY-UIN" />
    <string name="last_login_uin">MY-UIN</string>
    <int name="default_uin" value="MY-UIN" />

运行结果中的一串数字MY-UIN是我的微信uin

获取EnMicroMsg.db

我们要根据uin计算EnMicroMsg.db所在的目录。下面代码中的MY-UIN要替换成从上一步得到的值。

uin=MY-UIN
folder=`echo -n mm$uin | md5`

下面代码是将EnMicroMsg.db拉到电脑上。

database="/data/data/com.tencent.mm/MicroMsg/$folder/EnMicroMsg.db"
tmpdb="/sdcard/EnMicroMsg.db"
adb shell su -c "cp $database $tmpdb"
adb pull $tmpdb
adb shell rm $tmpdb

计算密码

在计算密码之前,我们还要知道手机的imei码。手机拨号*#06#就可以得到自己手机的imei。假设我的imeiMY-IMEI

imei=MY-IMEI
echo -n $imei$uin | md5 | cut -c -7
xxxxxxx

这样计算出来7位字符串就是数据库的密钥。网上有很多教程都是直接使用SQLCipher的数据库浏览器打开EnMicroMsg.db然后输入密码xxxxxxx的。但是使用这种直接的方法在我的MacBook Air上总是失败。我是根据这篇文章解密数据库的。

安装SQLCipher

我使用homebrew安装。

brew update
brew install sqlcipher

解密数据库

首先cdEnMicroMsg.db所在的文件夹,然后运行SQLCipher

sqlcipher

然后依次执行以下SQL语句解密数据库。

.open EnMicroMsg.db
PRAGMA key='xxxxxxx';
PRAGMA cipher_use_hmac=off;
PRAGMA cipher_page_size=1024;
PRAGMA kdf_iter=4000;
ATTACH DATABASE 'MicroMsg.db' AS mm KEY '';
SELECT sqlcipher_export('mm');
DETACH DATABASE mm;
.quit

正确执行之后,在EnMicroMsg.db文件夹中会多出一个解密后的数据库:MicroMsg.db。这个数据库中的message表格存有聊天记录,rcontact存有联系人信息。

聊天词云

有了这个聊天记录MicroMsg.db,我们可以做很多事情。比如做个聊天词云什么的。

from wordcloud import WordCloud
import matplotlib.pyplot as plt
import jieba
import sqlite3


def wechat_wordcloud(talker):
    font_path = "DroidSansFallbackFull.ttf"
    data = wechat_record(talker)
    img = WordCloud(font_path=font_path, width=1400, height=1400,
                    margin=2, collocations=False).generate(data)
    plt.imshow(img)
    plt.axis("off")
    plt.show()
    img.to_file("{}.png".format(talker))


def wechat_record(talker):
    conn = sqlite3.connect("MicroMsg.db")
    c = conn.cursor()
    stmt = "SELECT content FROM message WHERE talker='{}'".format(talker)
    msg = []
    for row in c.execute(stmt):
        if not row or not row[0] or row[0].find('xml') != -1:
            continue
        msg.append(row[0])
    msg = "\n".join(msg)
    wordfilter = list("abcdefghijklmnopqrstquvwxyz0123456789")
    for wf in wordfilter:
        msg = msg.replace(wf, "")
    data = " ".join(jieba.cut(msg, cut_all=True))
    conn.close()
    return data


if __name__ == '__main__':
    talker = "FRIEND-ID"
    wechat_wordcloud(talker)

我所使用的字体可以在这里下载。代码中的FRIEND-ID要正确填写朋友的id(在rcontact表格中找)。最后放上我跟我基友的聊天词云。

聊天词云