【好玩的小demo】微信&QQ聊天数据统计分析

突发奇想,想统计一下读研期间和导师的聊天记录,分析一下。实现的效果如下:

完整代码见:wechat_ana: 微信、QQ聊天记录分析 - Gitee.com

聊天记录获取

1. 微信

微信聊天记录需要手机root,从而获得数据库,再对数据库进行解密,得到聊天记录信息[1]。如果手机不想root,也可通过电脑端的模拟器获取[2]。这里使用蓝叠4[3]

(1)登录电脑端微信,将聊天记录全部导出:

(2)在蓝叠模拟器中安装微信,并登录,将聊天记录导出到模拟器手机端。

(3)取得模拟器root权限:

(4)在R.E.管理器中找到路径“/data/data/com.tencent.mm/MicroMSg”,进入下方的一个乱码文件夹:

(5)将 EnMicroMsg.db 文件移动到电脑上。

蓝叠:长按文件,复制到 /sdcard/windows/BstSharedFolder

本地:<...>\BluestacksCN\Engine\ProgramData\Engine\UserData\SharedFolder

即可在本地蓝叠安装路径下找到。

(6)下载 sqlcipher,读取数据库。

百度网盘 请输入提取码 (密码:kfe2)

(7)解压密码由手机IMEI码+微信uin码经过md5的32位(小)解密的前7位组成。

模拟器默认IMEI码:1234567890ABCDEF

uin码:打开文件“/data/data/com.tencent.mm/shared_prefs/auth_info_key_prefs.xml”,

使用md5[4]对IMEI+uin加密:

 前7位即为解压密码。

(8)用sqlcipher打开EnMicroMsg.db,导出为csv文件:

 选择message:

2. QQ

qq的聊天记录导出十分简单,也不用解密。

登录电脑端QQ,打开消息管理:

 右键对应联系人,导出聊天消息,选择txt格式:

分析说明

1. 微信

 (1)导入的聊天记录是多个人的,需要找一下想要分析的人的编号,进行对应。

对于个人聊天,“talker”为“wxid_xxxxx”;对于群聊,“talker”为“xxxx@chatroom”。或者也可用talkerId进行区分。

(2)数据统计时,统计全部信息。而词云分析时,我们只对聊天文本进行分析,需要排除语音、图片、视频、位置共享等信息的影响。

打开导出的.csv文件,可以发现,聊天记录的“type”为1时,聊天内容为文本信息。但群聊中,“content”下除了文本内容,还有发言人的id信息,在分析词语时需要进行清除:

需注意将.csv文件改为utf-8编码。

2. QQ

导出的聊天记录文件为单人,且格式均为:日期一行,n行信息,一行空格。

代码实现

代码结构:

data/下保存导出的.csv文件,mask/ 存放输出词云图片的形状掩码图,需图片背景部分为白色,outputs/ 保存输出的聊天记录分析等。

analyze.py为微信聊天记录分析类,qq.py为QQ聊天记录分析类,worldCloud.py为词云生成类[5],在test.py中调用整体方法。

微信

1. 根据.csv文件,列出字典PEOPLE,如:

PEOPLE = {
    'user1' :'548758976@chatroom',
    'user2' :'wxid_fsg768gh9fgh6',
}

其中字典key为用户昵称,value为.cvs文件中的talker。

2. 读取所有聊天记录,初始化,所有信息均保存在self.chat_all中:

def getData(self):
    # type,isSend,time,talker,content
    chat = pd.read_csv(self.data_path, sep=',', usecols=[2,4,6,7,8])

    # 对于每一条聊天数据
    for i in range(len(chat) - 1):
        content = chat[i:i + 1]

        # 如果是跟当前想分析的那个人的
        if content['talker'].values[0] == PEOPLE[self.people_name]:
            type = content['type'].values[0]
            isSend = content['isSend'].values[0]
            t = content['createTime'].values[0] // 1000
            c = content['content'].values[0]
            self.chat_type.append(type)
            self.chat_isSend.append(isSend)
            self.chat_time.append(t)
            self.chat_content.append(c)
            self.chat_all.append([type, isSend, t, c])

    self.chat_all = sorted(self.chat_all, key=itemgetter(2))  # 以时间顺序排序

3. 保存纯文字聊天记录信息于data/user1/all_chat.txt,用于后续词云分析:

def saveChat(self):
    # 1.根据type
    msg = []
    for i, line in enumerate(self.chat_content):
        if self.chat_type[i] == 1: # 文本信息
            # 2.个人聊天直接保存,群聊需去掉用户名
            if re.match(r'.*(chatroom)', PEOPLE[self.people_name]):
                if re.match(r'(wxid).*', line):
                    line = ''.join(line.split('\n')[1:])

            msg.append(line+'\n')

    writ2txt(''.join(msg), os.path.join(self.save_data_path, 'all_chat.txt'))

4. 聊天时间统计图画图,show=True时显示该图片,图片保存在outputs/user1/chat_time.png:

def draw(self, show=False):
    myfont = FontProperties(fname=r'C:\Windows\Fonts\MSYH.TTC', size=22)  # 标题字体样式
    myfont2 = FontProperties(fname=r'C:\Windows\Fonts\MSYH.TTC', size=18)  # 横纵坐标字体样式
    sns.set_style('darkgrid')  # 设置图片为深色背景且有网格线
    sns.distplot(self.hour_set, 24, color='lightcoral')
    plt.xticks(np.arange(0, 25, 1.0), fontsize=15)
    plt.yticks(fontsize=15)
    plt.title('聊天时间分布', fontproperties=myfont)
    plt.xlabel('时间段', fontproperties=myfont2)
    plt.ylabel('聊天时间分布', fontproperties=myfont2)
    fig = plt.gcf()
    fig.set_size_inches(20, 10)
    fig.savefig(os.path.join(self.outputs_path, 'chat_time.png'), dpi=100)
    if show:
        plt.show()

5. 聊天时段数据统计,late=True表示额外保存22点到次日凌晨2点的消息:

def timeSta(self, late=False):
    time_slice = [0, 0, 0, 0, 0, 0]
    labels = ['凌晨2点至6点', '6点至10点', '10点至14点',
              '14点至18点', '18点至22点', '22点至次日凌晨2点']
    deep_night = []  # 22-02点

    for i in range(len(self.hour_set)):
        if self.hour_set[i] >= 2 and self.hour_set[i] < 6:
            time_slice[0] += 1
        elif self.hour_set[i] >= 6 and self.hour_set[i] < 10:
            time_slice[1] += 1
        elif self.hour_set[i] >= 10 and self.hour_set[i] < 14:
            time_slice[2] += 1
        elif self.hour_set[i] >= 14 and self.hour_set[i] < 18:
            time_slice[3] += 1
        elif self.hour_set[i] >= 18 and self.hour_set[i] < 22:
            time_slice[4] += 1
        else:
            time_slice[5] += 1
            if late:
                deep_night.append([self.chat_time[i], self.chat_content[i]])

    time_distribution = {
        labels[0]: time_slice[0],
        labels[1]: time_slice[1],
        labels[2]: time_slice[2],
        labels[3]: time_slice[3],
        labels[4]: time_slice[4],
        labels[5]: time_slice[5]
    }

    print("共计聊天记录: {}条".format(len(self.chat_content)))
    print(time_distribution)
    write2txt("共计聊天记录: {}条".format(len(self.chat_content)), os.path.join(self.outputs_path, 'out.txt'))
    write2txt(time_distribution, os.path.join(self.outputs_path, 'out.txt'))

    # 深夜聊天记录统计
    if late:
        wbk = xlwt.Workbook()
        sheet = wbk.add_sheet('late')
        for i in range(len(deep_night)):
            sheet.write(i, 0, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(deep_night[i][0])))
            sheet.write(i, 1, deep_night[i][1])
        wbk.save(os.path.join(self.save_data_path, 'late_chat.xls'))

6. 关键字、字符统计:

def countChar(self):
    pattern1 = '.*?(收到).*?'
    pattern2 = '.*?(好的).*?'
    pattern3 = '.*?(老师).*?'
    pattern4 = '.*?(论文).*?'
    pattern5 = '.*?(可以).*?'
    pattern_set = [pattern1, pattern2, pattern3, pattern4, pattern5]
    statistic = [0, 0, 0, 0, 0]

    for i in range(len(self.chat_content)):
        for j in range(len(pattern_set)):
            length = len(re.findall(pattern_set[j], str(self.chat_content[i])))
            statistic[j] += length

    result = {
        '收到': statistic[0],
        '好的': statistic[1],
        '老师': statistic[2],
        '论文': statistic[3],
        '可以': statistic[4]
    }

    print(result)
    write2txt(result, os.path.join(self.outputs_path, 'out.txt'))

统计信息将保存在outputs/user1/out.txt中,其中关键词可以任意修改个数和内容,或者得到词云图后根据词云图来设置统计。

7. 发送消息条数统计:

def countPeoNum(self):
    self_num = 0
    people_num = 0

    for f in self.chat_isSend:
        if f==1:
            self_num += 1
        else:
            people_num += 1

    p = "自己发送的信息条数:{},对方发送的信息条数:{}".format(self_num, people_num)
    print(p)
    write2txt(p, os.path.join(self.outputs_path, 'out.txt'))

QQ

跟微信实现的方法相同,由于聊天记录的保存形式不同,仅getData方法的实现有所不同。

def getData(self):
    lines = open_txt(self.data_path, True)

    for line in lines: # 对于每条聊天记录
        # 如果不是发送时间和发送内容,就跳过
        if (line == '' or line == '='*64):
            continue
        strs = [r'消息.*']
        if isMatch(strs, line):
            continue

        # 日期文本, xxxx-xx-xx xxxxxxx
        if re.match(r'[0-9]{4}-[0-9]{2}-[0-9]{2}.*', line):
            self.chat_time.append(line.split(' ')[1])
            if line.split(' ')[2]==PEOPLE[self.people_name]:
                self.send_num += 1
            continue

        # 内容文本
        self.content.append(line)

跳过所有的空白行、日期行,其余行均保存在self.content中,用于后续词云分析。

使用

from analyze import WeChatData
from qq import QQData
from wordCloud import MyWordCloud


def main():
    chat_file = r"data\xxx\xxx.txt"
    name = 'xxx'

    # Data = WeChatData(chat_file, name, refresh=False) # 微信聊天内容统计
    Data = QQData(chat_file, name, refresh=True) # QQ聊天内容统计

    Data.saveChat()
    Data.draw()
    Data.timeSta()
    Data.countPeoNum()
    Data.countChar()


    # 生成词云
    if True:
        txt_path = Data.getChatPath()
        mask_path = r"mask\flower.png"
        save_path = r"outputs\{}\wordcloud.png".format(name)
        MyWordCloud(txt_path, mask_path, save_path)()



if __name__ == '__main__':
    main()

参考文档

[1] 爱情大数据 | 你的专属微信聊天记录统计

[2] 微信聊天记录统计

[3] BlueStacks蓝叠4

[4] MD5在线加密-站长工具

[5] 如何用Python做词云?

[6] 词云库wordcloud中文乱码解决办法

  • 4
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值