大家好,我是机灵鹤。

今天是跟女朋友在一起 10 个月的纪念日,作为一名会 Python 的程序员,我决定将和女朋友的聊天记录导出来,生成一份专属于我们的《2021 恋爱年度报告》。

感兴趣的朋友也可以学起来。

废话不多说,直接进入正题。

0. 导出聊天记录

由于破解微信聊天数据库的操作相对比较敏感,感兴趣的朋友可以移步《微信聊天记录导出教程》。

经过一系列操作,我从微信数据库中导出了跟女朋友的聊天记录。

聊天记录数据表 message.csv 格式如下。

其中,我们只需要关注以下几列即可。

  • type :消息类型,如 1 表示文字,3 表示图片,47 表示表情包
  • status :消息状态,2 表示发送的消息,4 表示接收的消息
  • createTime :发送时间,毫秒级时间戳
  • content :消息内容
  • imgPath :图片路径,如果是图片消息,则显示图片的 md5 值
  • talkerId :聊天对象的 ID

1. 聊天记录分析

本节中,我会使用 Python 对聊天记录文件进行数据分析,生成数据报告。

首先导入用到的模块,如果没有则需要安装。

# 用于读取和处理csv数据
import pandas as pd
# 用于处理日期,时间戳等数据
import time, datetime
# 用于生成直方图等图表
import matplotlib.pyplot as plt
# 用于对聊天内容进行分词处理
import jieba
# 用于生成词云图
from wordcloud import WordCloud,STOPWORDS,ImageColorGenerator
# 用于统计数组中元素出现次数
from collections import Counter
# 用于正则表达式提取数据
import re

然后读取 message.csv 文件。

# 需要读取的数据列
cols = ["type", "status", "createTime", "content", "imgPath", "talkerId"]
# message.csv 文件所在路径
filename = "src/message.csv"
# 女朋友的talkerId
TalkerID = 162
# 读取文件
data = pd.read_csv(filename, usecols=cols)

1.1 聊天消息概况统计

表中 type 列的值与消息类型对应情况,如下:

type 对应的消息类型
1 文字
2 图片
3 定位
34 语音
43 视频
47 表情包
49 分享链接
10000 撤回消息
822083633 引用回复
922746929 拍一拍
419430449 转账红包
486539313 公众号分享
754974769 视频号分享
1040187441 音乐分享
1090519089 传文件

注:以上是我通过比对微信聊天记录,大概推测所得,仅供参考,不一定对。

通过以下代码,可以统计得到聊天消息概况。

# 聊天消息总数
chatNum = 0
# 自己发送的消息
sendNum = 0
# 女朋友发送的消息
recvNum = 0
# 自己发送的消息总字数
hhMsgLen = 0
# 女朋友发送的消息总字数
yyMsgLen = 0
# 自己发送的最长消息的字数
hhMaxLen = 0
# 女朋友发送的最长消息的字数
yyMaxLen = 0
# 自己发送的长消息数(字数大于50)
hhLongMsg = 0
# 女朋友发送的长消息数(字数大于50)
yyLongMsg = 0# 文字消息数
textNum = 0
# 图片消息数
imageNum = 0
# 语音消息数
audioNum = 0
# 视频消息数
videoNum = 0
# 表情包数
emojiNum = 0
# 其他未分类消息
other = 0
# 分享消息数
shareNum = 0
# 发送文件数
fileNum = 0
# 引用回复数
replyNum = 0
# 转账红包数
moneyNum = 0
# 定位消息数
locaNum = 0
# 拍一拍数
pypNum = 0
# 撤回消息数
retrNum = 0# 统计消息条数
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():# 限定聊天对象是女朋友if talkerId == TalkerID:chatNum += 1if status == 2:sendNum += 1elif status == 4:recvNum +=1if msgType == 1:textNum += 1if status == 2:hhMsgLen += len(content)hhMaxLen = max(hhMaxLen, len(content))if len(content) >= 50:hhLongMsg += 1elif status == 4:yyMsgLen += len(content)yyMaxLen = max(yyMaxLen, len(content))if len(content) >= 50:yyLongMsg += 1elif msgType == 3:imageNum += 1elif msgType == 34:audioNum += 1elif msgType == 43:videoNum += 1elif msgType == 47:emojiNum += 1# 链接分享,公众号分享,视频号分享,音乐分享等统一计入分享消息数elif msgType == 49 or msgType == 486539313 or msgType == 754974769 or msgType == 1040187441:shareNum += 1elif msgType == 822083633:replyNum += 1elif msgType == 1090519089:fileNum += 1elif msgType == 419430449 or msgType == 436207665:moneyNum += 1elif msgType == 10000:retrNum += 1elif msgType == 922746929:pypNum += 1elif msgType == 48 or msgType == -1879048186:locaNum += 1else:other += 1# 打印统计结果
print("聊天记录概况统计\n")
print("消息总条数:", chatNum)
print("---"*10)
print("鹤鹤发的消息数:", sendNum)
print("颖颖发的消息数:", recvNum)
print("鹤鹤发送的总字数:", hhMsgLen)
print("颖颖发送的总字数:", yyMsgLen)
print("鹤鹤发送的长消息数:", hhLongMsg, ",最长消息", hhMaxLen, "字")
print("颖颖发送的长消息数:", yyLongMsg, ",最长消息", yyMaxLen, "字")
print("---"*10)
print("文字:", textNum)
print("表情包:", emojiNum)
print("图片:", imageNum)
print("语音:", audioNum)
print("视频:", videoNum)
print("---"*10)
print("链接分享:", shareNum)
print("引用回复:", replyNum)
print("发送文件:", fileNum)
print("红包转账:", moneyNum)
print("撤回消息:", retrNum)
print("拍一拍:", pypNum)
print("发送定位:", locaNum)
print("---"*10)
print("未分类:", other)

运行结果

聊天记录概况统计消息总条数: 107456
------------------------------
鹤鹤发的消息数: 51753
颖颖发的消息数: 55692
鹤鹤发送的总字数: 459031
颖颖发送的总字数: 450474
鹤鹤发送的长消息数: 220 ,最长消息 459 字
颖颖发送的长消息数: 64 ,最长消息 254 字
------------------------------
文字: 93334
表情包: 9227
图片: 2452
语音: 186
视频: 212
------------------------------
链接分享: 102
引用回复: 1541
发送文件: 20
红包转账: 30
撤回消息: 227
拍一拍: 102
发送定位: 9
------------------------------
未分类: 14

1.2 聊天时间段分析

根据数据表中的 createTime 字段,可以获取到消息发送的时间,进而可以进行聊天时间段分析。

1.2.1 每天聊天消息数

# 定义字典,键为日期,值为该天聊天消息数
dayMsgDict = {}# 统计每天的聊天消息数
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:timeArray = time.localtime(createTime/1000)date = time.strftime('%Y-%m-%d', timeArray)if dayMsgDict.get(date):dayMsgDict[date] += 1else:dayMsgDict.setdefault(date, 1)# 绘制直方图可视化展示
plt.figure(figsize=(15, 10))
plt.bar(range(len(dayMsgDict.keys())), dayMsgDict.values())
plt.show()

运行结果

1.2.2 每月的聊天消息数

# 定义数组,从2020年10月起,至2022年1月,共 16 个月
monMsgArray = [0] * 16# 统计每月的聊天消息数
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:timeArray = time.localtime(createTime/1000)if timeArray.tm_year == 2020:monMsgArray[timeArray.tm_mon - 10] += 1elif timeArray.tm_year == 2021:monMsgArray[timeArray.tm_mon + 2] += 1if timeArray.tm_year == 2022:monMsgArray[-1] += 1# 绘制直方图可视化展示
plt.figure(figsize=(15, 10))
month_Label = ["20-Oct", "20-Nov", "20-Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "22-Jan"]
plt.bar(range(len(monMsgArray)), monMsgArray, tick_label=month_Label)
plt.show()

运行结果

1.2.3 一周的聊天消息数

# 定义数组,从周一到周日,每天的聊天消息数
weekMsgArray = [0] * 7# 统计从周一到周日,每天的聊天消息数
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:weekday = datetime.datetime.fromtimestamp(createTime/1000).weekday()weekMsgArray[weekday] += 1# 绘制直方图可视化展示
plt.figure(figsize=(15, 10))
weekday_Label = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
plt.bar(range(len(weekMsgArray)), weekMsgArray, tick_label=weekday_Label)
plt.show()

运行结果

1.2.4 一天的聊天消息数

# 定义数组,一天24小时
hourMsgArray = [0] * 24# 统计一天24小时的聊天消息数
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:timeArray = time.localtime(createTime/1000)hourMsgArray[timeArray.tm_hour] += 1# 绘制直方图可视化展示
plt.figure(figsize=(15, 10))
hour_Label = [str(i) for i in range(0, 24)]
plt.bar(range(len(hourMsgArray)), hourMsgArray, tick_label=hour_Label)
plt.show()

运行结果

1.2.5 一些特别的日子

聊天最多的一天

# 聊天最多的一天,以及这天的聊天消息数
maxDay = 0
maxVal = 0for key in dayMsgDict:if maxVal < dayMsgDict[key]:maxDay = keymaxVal = dayMsgDict[key]# 打印统计结果
print(maxDay, "这一天,你们无话不谈,聊了", maxVal, "句")

运行结果

2021-03-28 这一天,你们无话不谈,聊了 909 句

聊天最晚的一天

这里我以凌晨 5 点作为分界点,5 点之前属于晚睡,5 点之后属于早起。

# 聊天最晚的一天
latestDay = None# 统计聊天最晚的一天
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:timeArray = time.localtime(createTime/1000)if timeArray.tm_hour < 5:if latestDay == None:latestDay = timeArraycontinuets1 = timeArray.tm_hour * 3600 + timeArray.tm_min * 60 + timeArray.tm_sects2 = latestDay.tm_hour * 3600 + latestDay.tm_min * 60 + latestDay.tm_secif ts1 > ts2:latestDay = timeArray#打印统计结果
Date = time.strftime('%Y-%m-%d', latestDay)
Time = time.strftime('%H点%M分', latestDay)
print(Date, "这一天,你们睡得很晚,凌晨",Time, "仍在聊天")

运行结果

2021-05-30 这一天,你们睡得很晚,凌晨 04点40分 仍在聊天

起床最早的一天

# 聊天最早的一天
earliestDay = None# 统计聊天最早的一天
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID:timeArray = time.localtime(createTime/1000)if timeArray.tm_hour >= 5:if earliestDay == None:earliestDay = timeArraycontinuets1 = timeArray.tm_hour * 3600 + timeArray.tm_min * 60 + timeArray.tm_sects2 = earliestDay.tm_hour * 3600 + earliestDay.tm_min * 60 + earliestDay.tm_secif ts1 < ts2:earliestDay = timeArray#打印统计结果
Date = time.strftime('%Y-%m-%d', earliestDay)
Time = time.strftime('%H点%M分', earliestDay)
print(Date, "这一天,你们醒得很早,早上",Time, "便已开启新的一天")

运行结果

2021-07-11 这一天,你们醒得很早,早上 05点26分 便已开启新的一天

1.3 聊天内容分析

1.3.1 最常说的词语

# 文字消息字符串
msgContent = ""# 开始统计
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID and msgType == 1:msgContent += content# 剔除 Emoji 表情
pattern = re.compile(r"\[.+?\]")
msgContent = pattern.sub(r"", msgContent)# jieba 分词
msg_all_split = jieba.cut(str(msgContent), cut_all=False)
# 剔除单字
all_ls = [word for word in msg_all_split if len(word)>1]
all_words = ' '.join(all_ls)# 设置停用词
stopwords = STOPWORDS.copy()
stopwords.add('这个')
stopwords.add('就是')
stopwords.add('什么')
stopwords.add('然后')
stopwords.add('可以')
stopwords.add('没有')
stopwords.add('一个')
stopwords.add('不是')
stopwords.add('感觉')
stopwords.add('时候')
stopwords.add('觉得')# 生成词云图
wc = WordCloud(width=1960, height=1080, background_color='white', font_path='STKAITI.TTF', stopwords=stopwords, max_font_size=400, random_state=50, collocations=False)
wc.generate_from_text(all_words)# 词云图显示
plt.figure(figsize=(15, 10))
plt.imshow(wc)
plt.axis('off')
plt.show()

运行结果

我最常说的词语

# 我发送的文字消息
hhMsgContent = ""# 开始统计
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID and msgType == 1:if status == 2:hhMsgContent += content# 剔除 Emoji 表情
pattern = re.compile(r"\[.+?\]")
msgContent = pattern.sub(r"", hhMsgContent)# jieba 分词
msg_all_split = jieba.cut(str(msgContent), cut_all=False)
# 剔除单字
all_ls = [word for word in msg_all_split if len(word)>1]
all_words = ' '.join(all_ls)# 设置停用词
stopwords = STOPWORDS.copy()# 生成词云图
wc = WordCloud(width=1960, height=1080, background_color='white', font_path='STKAITI.TTF', stopwords=stopwords, max_font_size=400, random_state=50, collocations=False)
wc.generate_from_text(all_words)# 词云图显示
plt.figure(figsize=(15, 10))
plt.imshow(wc)
plt.axis('off')
plt.show()

运行结果:

女朋友最常说的词语

# 女朋友发送的文字消息
yyMsgContent = ""# 开始统计
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID and msgType == 1:if status == 4:yyMsgContent += content# 剔除 Emoji 表情
pattern = re.compile(r"\[.+?\]")
msgContent = pattern.sub(r"", yyMsgContent)# jieba 分词
msg_all_split = jieba.cut(str(msgContent), cut_all=False)
# 剔除单字
all_ls = [word for word in msg_all_split if len(word)>1]
all_words = ' '.join(all_ls)# 设置停用词
stopwords = STOPWORDS.copy()# 生成词云图
wc = WordCloud(width=1960, height=1080, background_color='white', font_path='STKAITI.TTF', stopwords=stopwords, max_font_size=400, random_state=50, collocations=False)
wc.generate_from_text(all_words)# 词云图显示
plt.figure(figsize=(15, 10))
plt.imshow(wc)
plt.axis('off')
plt.show()

运行结果

1.3.2 最常用的Emoji表情

# 正则表达式,提取聊天文字中的emoji表情
pattern = re.compile(r"\[.+?\]")# hhMsgContent 为前面统计好的我发的文字消息
hhEmoji = re.findall(pattern, hhMsgContent)
# yyMsgContent 为前面统计好的女朋友发的文字消息
yyEmoji = re.findall(pattern, yyMsgContent)# 按照出现次数统计
hh = Counter(hhEmoji)
yy = Counter(yyEmoji)# 打印统计结果
print("鹤鹤发的表情数:", len(hhEmoji))
print("颖颖发的表情数:", len(yyEmoji))
print("---"*10)
print ("鹤鹤最常用的 10 个表情:\n", hh.most_common(10))
print("---"*10)
print ("颖颖最常用的 10 个表情:\n", yy.most_common(10))

运行结果

鹤鹤发的表情数: 15768
颖颖发的表情数: 21531
------------------------------
鹤鹤最常用的 10 个表情:[('[破涕为笑]', 5083), ('[捂脸]', 4792), ('[偷笑]', 1829), ('[让我看看]', 1361), ('[奸笑]', 373), ('[发呆]', 318), ('[嘿哈]', 268), ('[皱眉]', 223), ('[苦涩]', 208), ('[憨笑]', 122)]
------------------------------
颖颖最常用的 10 个表情:[('[破涕为笑]', 9462), ('[让我看看]', 5413), ('[捂脸]', 2459), ('[苦涩]', 2062), ('[旺柴]', 944), ('[偷笑]', 231), ('[白眼]', 154), ('[发呆]', 64), ('[奸笑]', 60), ('[666]', 55)]

这样看可能看不出来,复制到微信里,就会显示对应的表情了。

1.3.3 最常发的表情包图片

# 我发送的表情包列表
hhImgList = []
# 女朋友发送的表情包列表
yyImgList = []# 统计数据
for index, msgType, status, createTime, content, imgPath, talkerId  in data.itertuples():if talkerId == TalkerID and msgType == 47:if status == 2:hhImgList.append(imgPath)elif status == 4:yyImgList.append(imgPath)# 统计每个表情包出现次数
hhImg = Counter(hhImgList)
yyImg = Counter(yyImgList)# 打印统计结果
print("鹤鹤共发送了", len(hhImgList), "个表情包")
print("颖颖共发送了", len(yyImgList), "个表情包")
print("---"*10)
print ("鹤鹤表情包前十名:\n", hhImg.most_common(10))
print("---"*10)
print ("颖颖表情包前十名:\n",yyImg.most_common(10))

运行结果

鹤鹤共发送了 4203 个表情包
颖颖共发送了 5024 个表情包
------------------------------
鹤鹤表情包前十名:[('6b5a13890545c9675e6029fbee395560', 319), ('d9f537281429695f9c299049814e3e33', 164), ('8fb0ddeea33701832c86167a141452df', 114), ('25b8abcd5318ded9ade61a6ec1287a95', 91), ('7f69ba3a4ed01d1c16c3b6576c45d24e', 90), ('4ce13465607eb3243d6e80e7a95b838f', 81), ('a9d5dbb4c0fba9a1af0ec2e6e064977b', 80), ('ce58baf1002411bdafd299a689cadfe4', 76), ('c1ed2b89e38cfded0461bc95db1ab522', 75), ('d16c0b43b9ee901d92f9542b1033234a', 70)]
------------------------------
颖颖表情包前十名:[('a9d5dbb4c0fba9a1af0ec2e6e064977b', 712), ('477e31cf6e2a747c96e1248a02605756', 352), ('e976c1e3f56a32db3c2f49de72daa616', 215), ('4d21237942192184a4c8a57ab34fb2fa', 183), ('125d7792a060cece7edef87d71b40837', 168), ('4ce13465607eb3243d6e80e7a95b838f', 151), ('7c04a4df048874f088dc8832c45e3fb6', 146), ('b2f427b22d1e581923837acd7165e882', 137), ('6b5a13890545c9675e6029fbee395560', 137), ('b83d0a5929cdf92aeb05eefaf3612bea', 92)]

:统计得到的 imgPath 值为表情包图片的 MD5 值,对应的表情包可以通过发送时间 createTime,在微信聊天记录中对照着找到。

2. 年度报告

将上面统计好的数据稍加整理,便得到了与女朋友微信聊天的《年度报告》。

鹤鹤年度表情包前十名

颖颖年度表情包前十名

鹤鹤年度聊天词云

颖颖年度聊天词云


欢迎关注公众号【机灵鹤】

我是机灵鹤,一个代码写的不错,还有点小浪漫的程序员。

手把手教你生成你的独家微信聊天年度报告相关推荐

  1. 手把手教你用鸿蒙HarmonyOS实现微信聊天界面(三)

    简介 本系列文章记录作者大三开学第一个月中学习HarmonyOS移动应用开发学习经历,此篇为<微信聊天界面>项目,实现功能有 1.聊天信息功能,包括图片.文字 2.发送定位功能 3.选择发 ...

  2. 手把手教你用鸿蒙HarmonyOS实现微信聊天界面(二)

    简介 本系列文章记录作者大三开学第一个月中学习HarmonyOS移动应用开发学习经历,此篇为<微信聊天界面>项目,实现功能有 1.聊天信息功能,包括图片.文字 2.发送定位功能 3.选择发 ...

  3. 手把手教你用鸿蒙HarmonyOS实现微信聊天界面(一)

    简介 本系列文章记录作者大三开学第一个月中学习HarmonyOS移动应用开发学习经历,此篇为<微信聊天界面>项目,实现功能有 1.聊天信息功能,包括图片.文字 2.发送定位功能 3.选择发 ...

  4. 手把手教你做短视频去水印微信小程序(2-首页)

    手把手教你做短视频去水印微信小程序系列教程(2-首页) 文章目录 手把手教你做短视频去水印微信小程序系列教程(2-首页) 前言 一.顶部banner 二.地址解析 1.整体代码 2. input框输入 ...

  5. python 词云手把手_手把手教你生成炫酷的词云

    前言: 话说,在这个大数据时代,获取信息显得极为容易,可正是如此,我们想要对信息进行直观地了解难度就大了.Excel是一个很好的数据可视化方法,不过有时候我们的数据来源可能并不是一张或者多张Excel ...

  6. 手把手教你最近很火的 微信公众号测试号推送消息

    最近有很多小伙伴在尝试做消息推送,今天详细教程它来啦!!! 过程不太复杂,跟着一步一步做就可以实现. 没时间的话,先收藏,等有时间了慢慢学! 第一步:注册微信公众号测试号 1.利用下面的链接注册一个微 ...

  7. 手把手教你如何将chatgpt接入微信公众号

    **众所周知,今年以来话题度最高的莫过于chatgpt,ChatGPT是一种基于GPT-3.5架构的大型语言模型,由OpenAI开发.它可以处理多种语言,包括英语.中文等等.ChatGPT通过在大量的 ...

  8. 手把手教你用图灵机器人做微信公众号自动回复助手

    本文首发于我的个人博客:尾尾部落 阅读这篇文章,你将会学会以下内容: 如何用flask搭建微信公众平台服务 如何将在微信公众平台调用图灵机器人 如何用uwsgi+supervisor+nginx部署f ...

  9. 手把手教你生成对抗网络 GAN,50 行代码玩转 GAN 模型!(附源码)

    来源:AI有道 本文约2820字,建议阅读12分钟. 本文为大家介绍了生成对抗网络(Generate Adversarial Network,GAN),以最直白的语言来讲解它,最后实现一个简单的 GA ...

最新文章

  1. Eureka与zookeeper
  2. 干货 | 大牛谈嵌入式C语言的高级用法
  3. oracle多线程删除,请教高手:多线程访问时如何实现删除一个文件?
  4. devops相关书籍哪个好_您在DevOps周期中的哪个位置进行安全保护?
  5. (47)网页布局常用工具
  6. 10分钟带你读完人工智能的三生三世
  7. BAPI_FIXEDASSET_OVRTAKE_CREATE 固定资产批导(历史遗留、折旧)
  8. stm32中的“hello world”
  9. Spring mvc 的生命周期
  10. 理解锁相环的工作原理
  11. 作为一名计算机学院普通的大学生如何提高兴趣敲代码?谈谈我的感受,欢迎交流
  12. 系统间对接 各个方案
  13. 记录UM8005 8位单片机的程序死机:aS
  14. 2018年网上最靠谱的正规赚钱思路
  15. 国际经济与贸易专业与计算机联系,经济与贸易专业(国际经济与贸易方向).docx...
  16. 云台摄像机的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  17. Maya建模学习笔记
  18. MT7628学习笔记(12)——GPIO操作,注册LED驱动
  19. android ViewPager制作广告栏
  20. 有人靠红包封面挣了十几万,微信官方回应

热门文章

  1. 贵州云计算机考试,贵州云计算专业大学哪个好
  2. 怎么用计算机录制mp3的音频,怎么在电脑上录制在线音频 高音质音频如何录制...
  3. 用友T3软件中批量输出明细账时科目顺序错乱
  4. 数学系考计算机四级考试内容及合格标准,2012全国计算机等级考试四级复习纲要六[3]...
  5. “聚光灯”下的数梦工场 首提“新型互联网”战略
  6. 六款顶级桌面美化软件推荐(Windows)
  7. MCS计算机科学,UVa弗吉尼亚大学计算机科学硕士MS/MCS. Computer Science
  8. Autolayout使用详细介绍
  9. 淘宝 商品定制 C2B 全流程。
  10. 根据json串直接入库