Python的情人节礼物:做一个与她微信聊天的词云吧

本文将使用情侣的微信聊天记录作为文本来源,是不是更情深意切,一虐方休。

本文的操作系统环境:iOS 10.2.1,macOS 10.12.3,用到了一个第三方的iOS设备管理工具工具iMazing,官网上是很贵的,淘宝上有团购的正版卖,便宜不少。编程环境为Python 3.6,使用Jupyter Notebook 4.2.1。

提取聊天记录数据

首先打开这个软件,映入眼帘的是如下界面。首先点击左侧的”文件系统“。之后,既可以选择最左边的“应用程序”,也可以选择最右边的“备份”。

第一步

先点击“备份”时

点击“备份”后

此时就要千辛万苦找到存放聊天记录的数据库的位置(这个路径网上都搜不到,有软件直接靠这个位置卖钱的,被我瞎猫碰死耗子找到了)

Apps/AppDomain-com.tencent.xin/Documents/04……015/DB/MM.sqlite

04……015是很长一串数字英文夹杂的文件夹名,可能文件夹因人而异的,可能Documents文件里有多个该类型文件夹,选择时间最新的那个。

先点击“应用程序”时

在其中找到微信,看到“文稿”由于iOS限制是无法访问的,只能点击“备份”。

点击“应用程序”找到微信并点开后

进去之后就会看到文件夹Documents,之后操作与上文一致。

导出数据库

找到上文所说的数据库之后,点击”拷贝至Mac“,保存到电脑某处就可以了。

数据库初窥

从扩展名可知,这是一个sqlite数据库,推荐一个免费软件叫sqlitebrowser,打开数据库后发现里面有好几百张(根据你的聊天记录条数而变化)表啊!每一张表代表着一个聊天对象,可能是群可能是人可能是公众号。到底妹子在哪一张表里呢?

数据库内容

我的SQL能力很差,只好通过python操作数据库,办法笨了点,编程大神不要笑我(笑我也无妨,我有女票)。

以下开始虐狗

提取聊天记录文本

import sqlite3 import pandas aspd conn=sqlite3.connect( '%s'% '.../MM.sqlite') #连接数据库cur=conn.cursor() query = "SELECT name FROM sqlite_master WHERE type='table' order by name"#查询所有表名a= pd.read_sql(query, conn) result= [] fori ina.name: #开始遍历所有表查找女票(的聊天记录)藏身之处query3 = "SELECT * FROM %s"%(i) r = pd.read_sql(query3, conn) if'Message'inr.columns: forj inr.Message: if'xxxxxx'inj: #注1,关键的一步result.append(i) query4 = "SELECT * FROM %s"%( result[ 0]) #注1那步完成得好,result就会只有一个元素text= pd.read_sql(query4, conn) text= list( text.Message) #注2full_text = '\n'.join( text) #将text这个列表合并成字符串,以回车符分隔f = open( '.../聊天记录.txt', 'w') f. write(full_text) f. close()

注1:选择你跟你女朋友的独特一句对话,用来查找。如果你发现你用”么么哒“、”我爱你“、”亲爱的“(微信会把官方表情以表情名称形式文本化存储,所以用这种词查找的效率不高)等搜出了好几个人的话,劝你还是先好好反省自己。——喔想到这里简直是给程序媛查岗男票的福利啊!

注2:经过我之前取特例观察,存放聊天记录的表名均为Chat_xxx,而其中的Message一列存放的即是聊天记录。

分词

以下代码我就不做详细解释了

import codecs import jieba file=codecs. open( '.../聊天记录.txt', 'r') content= file. read() file. close() segment=[] segs=jieba.cut(content) #分词forseg insegs: iflen(seg)> 1andseg!= '\r\n': segment.append(seg) words_df=pd.DataFrame({ 'segment':segment}) del segment #将segment转换成DataFrame后删掉,释放内存

我的结果是:文本共有17w+行,分出了100w个词汇(重复计数)。因此用Spyder处理时候已经卡到不行了,换用Jupyter IPython Notebook反而十分流畅,难怪好多大神也是用Notebook做的。

停用词库

文本挖掘的第一步分词之后的重要步骤是排除无用词语,业内称作”停用词“。我设定的停用词分为两个来源:

1.由于微信中分享的网页会以地址的形式以文本存在聊天记录里,被分词分开,因此需要排除,为了方便,直接在分词结果中的所有非中文词汇放入停用词库。这里一个trick是:将聊天里会使用到的高频英文、数字加回分词列表,例如233、666、mac、app之类的。

2.通用的停用词库,这个库里包含了大量的连词、副词等,可见《中文停用词词表》所做的工作,我直接拿来用了。

3.其他无用词语。例如微信中的”xx撤回了一条消息”也会在记录里。不过如果你发现你的记录里”撤回“的频率特别高……你们真的不是在玩Snapchat?

exclusive = [] #建立一个停用词列表fori inwords_stat.segment: ifre.findall( r'[A-Za-z0-9]*', i)[ 0] != '': #通过正则式表达排除英文、数字。findall返回的是一个列表exclusive.append(i) forj in[ '666', '233', '2333', 'App', 'app', 'Mac', 'mac']: #我的举例,读者可自行添加exclusive.remove(j) #从排除列表中删去这些需要保留的词汇ex = [ '撤回'] #举例fore inex: exclusive.append(e) stop = '\n'.join(exclusive) f = open( '.../stopwords.txt', 'w') f.write(stop) f.close() stopwords1=pd.read_csv( ".../stopwords.txt", index_col= False,quoting= 3,sep= "\t",names=[ 'stopword'],encoding= "utf8") stopwords2=pd.read_csv( ".../停用词库.txt", index_col= False,quoting= 3,sep= "\t",names=[ 'stopword'],encoding= "utf8") #第三方停用词库stopwords = stopwords1.append(stopwords2) words_df=words_df[~words_df.segment.isin(stopwords.stopword)] #用停用词库更新分词列表words_stat=words_df.groupby(by=[ 'segment'])[ 'segment'].agg({ "计数":np.size}) #计算频率words_stat=words_stat.reset_index().sort(columns= "计数",ascending= False)大功告成 importmatplotlib.pyplot asplt fromwordcloud importWordCloud fromscipy.misc importimread importmatplotlib.pyplot asplt fromwordcloud importWordCloud,ImageColorGenerator fromscipy.misc importimread bimg=imread( '.../love.png') #背景图片wordcloud=WordCloud(font_path= "simhei.ttf",background_color= "white",mask = bimg,max_font_size= 600,random_state= 100) #背景设成白的比较合适,我感觉;max_font_size和random_state自己调咯wordcloud=wordcloud.fit_words(words_stat.head( 4000).itertuples(index= False)) #词频排名前多少的放到图里bimgColors=ImageColorGenerator(bimg) plt.figure() plt.imshow(wordcloud.recolor(color_func=bimgColors)) plt.axis( "off") plt.show() wordcloud.to_file( "结果.png") #存成文件最后

1有什么各种不让你满意的地方多多包涵

2郑重提醒:该礼物只能作为锦上添花,使用本教程导致情人节变情人劫的,本人概不负责……

3我有一个Python学习交流QQ群:638121273 禁止闲聊,非喜勿进。