Illustrations by Evgenij Kungur 文/ Python攻城獅
最近研究了一下itchat和matplotlib,目前實現(xiàn)了對微信好友頭像、性別、區(qū)域、個性簽名的采集及展示。
本文就來詳細介紹一下這個庫的用法和一些核心邏輯實現(xiàn)。
1.微信登錄 import itchat itchat.auto_login(hotReload=True ) itchat.dump_login_status()
we_friend = itchat.get_friends(update=True )[:]
這里的we_friend
是好友的信息的列表,每一個好友字典的 key 如下表
key 備注 UserName 微信系統(tǒng)內的用戶編碼標識 NickName 好友昵稱 Sex 性別 Province 省份 City 城市 HeadImgUrl 微信系統(tǒng)內的頭像URL RemarkName 好友的備注名 Signature 個性簽名
有了key對應的值,我們就好處理了。
2.好友性別 這里順便提一下:如果sex=1則代表男性,sex=2代表女性
total = len(we_friend[1:])for fri_info in we_friend[1:]: sex = fri_info['sex' ] # 如果sex=1 代表男性 sex=2代表女性 if sex == 1: man += 1 elif sex == 2: woman += 1 else : other += 1
統(tǒng)計出男生、女生的以及總人數(shù)后,占比自然而然就出來了,為了更好的展示男女比例,我們以餅圖展示。
man_ratio = int (man)/total * 100 woman_ratio = int (woman)/total * 100 other_ratio = int (other)/total * 100 plt.rcParams['font.sans-serif' ] = ['SimHei' ] # 用來正常顯示中文標簽 plt.rcParams['axes.unicode_minus' ] = False # 用來正常顯示負號 plt.figure(figsize=(5 , 5 )) # 繪制的圖片為正圓 sex_li = ['男' , '女' , '其他' ] radius = [0.01 , 0.01 , 0.01 ] # 設定各項距離圓心n個半徑 colors = ['red' , 'yellowgreen' , 'lightskyblue' ] proportion = [man_ratio, woman_ratio, other_ratio] plt.pie(proportion, explode=radius, labels=sex_li, colors=colors, autopct='%.2f%%' ) # 繪制餅圖 # 加入圖例 loc = 'upper right' 位于右上角 bbox_to_anchor=[0.5, 0.5] # 外邊距 上邊 右邊 borderaxespad = 0.3圖例的內邊距 plt.legend(loc='upper right' , fontsize=10 , bbox_to_anchor=(1.1 , 1.1 ), borderaxespad=0.3 )# 繪制標題 plt.title('微信好友性別比例' ) # 展示 plt.show()
微信好友性別比例 作為一個碼農(nóng)、程序猿,還能有這么多女性好友實屬不易啊。敏感的我,看了這個比例深深地感覺到了不安,(此圖女朋友不可見 )另外,怎么還有一些未知生物的存在…
友情提醒:matplotlib中文亂碼這個問題一直存在,這里記錄下如何解決matplotlib中文亂碼
import matplotlibprint (matplotlib.matplotlib_fname()) # 查看路徑
font .family : sans-serif font .serif : SimHei , DejaVu Serif , Bitstream Vera Serif , New Century Schoolbook , Century Schoolbook L , Utopia , ITC Bookman , Bookman , Nimbus Roman No9 L , Times New Roman , Times , Palatino , Charter , serif
在terminal中:cd ~/.cache/matplotlib 把.cache下面的matplotlib文件夾刪除。 $ rm -rf matplotlib
3.微信好友頭像 這里其實看過我之前文章的應該知道,其實頭像的拼接主要分為兩部分
import os num = 0 pwd_path = os .path .abspath(os .path .dirname(os .getcwd())) desc_photos = os .path .join(pwd_path, 'res/photos' )for i in friends: img = itchat.get_head_img(userName=i['UserName' ]) file_image = open (desc_photos + '/' + str(num) + '.jpg' , 'wb' ) file_image.write (img) file_image.close () num += 1
ls = os.listdir(desc_photos) each_size = int(math.sqrt(float(640 * 640) / len(ls))) # 算出每張圖片的大小多少合適 lines = int(640 / each_size) image = Image.new('RGBA', (640, 640)) # 創(chuàng)建640*640px的大圖 x = 0 y = 0 for i in range(0, len(ls) + 1): try: img = Image.open(desc_photos + '/' + str(i) + '.jpg' ) except IOError: print('Error' ) else : img = img.resize((each_size, each_size), Image.ANTIALIAS) image.paste(img, (x * each_size, y * each_size)) # 粘貼位置 x += 1 if x == lines: # 換行 x = 0 y += 1 image.save(desc_full + '/好友頭像拼接圖.jpg' )
密集恐懼癥患者請忽略!!!
好友頭像拼接 4.微信好友地區(qū)分布 獲取區(qū)域及城市
prov_dict, city_dict = {}, {}for fri_info in we_friend[1 :]: prov = fri_info['province' ] city = fri_info['city' ] if prov and prov not in prov_dict.keys(): prov_dict[prov] = 1 elif prov: prov_dict[prov] += 1 if city and city not in city_dict.keys(): city_dict[city] = 1 elif city: city_dict[city] += 1
由于城市太多,我們取好友數(shù)量排名前十的城市及區(qū)域進行展示,感興趣的可以稍微改下代碼,就可以展示所有區(qū)域人數(shù)。
排序這里我用了Python的sorted()
函數(shù),列表的每個元素都為二維元組,key
參數(shù)傳入了一個lambda函數(shù)
,其x就代表列表里的每一個元素,然后分別利用索引返回元素內的第一個和第二個元素,這就代表了sorted()
函數(shù)利用哪一個元素進行排列。而reverse
決定是正序還是倒序,默認為False。
# 區(qū)域Top10 prov_dict_top10 = sorted(prov_dict.items(), key=lambda x: x[1 ], reverse=True )[0 :10 ]# 城市Top10 city_dict_top10 = sorted(city_dict.items(), key=lambda y: y[1 ], reverse=True )[0 :10 ]
prov_nm, prov_num = [], [] # 省會名 + 數(shù)量 for prov_data in prov_dict_top10: prov_nm.append(prov_data[0 ]) prov_num.append(prov_data[1 ]) pwd_path = os.path.abspath(os.path.dirname(os.getcwd())) desc_full = os.path.join(pwd_path, 'res' ) colors = ['#00FFFF' , '#7FFFD4' , '#F08080' , '#90EE90' , '#AFEEEE' , '#98FB98' , '#B0E0E6' , '#00FF7F' , '#FFFF00' , '#9ACD32' ] plt.rcParams['font.sans-serif' ] = ['SimHei' ] # 用來正常顯示中文標簽 plt.rcParams['axes.unicode_minus' ] = False # 用來正常顯示負號 index = range(len(prov_num)) plt.bar(index, prov_num, color=colors, width=0.5 , align='center' ) plt.xticks(range(len(prov_nm)), prov_nm) # 橫坐軸標簽 for x, y in enumerate(prov_num): # 在柱子上方1.2處標注值 plt.text(x, y + 1.2 , '%s' % y, ha='center' , fontsize=10 ) plt.ylabel('省會好友人數(shù)' ) # 設置縱坐標標簽 prov_title = '微信好友區(qū)域Top10' plt.title(prov_title) # 設置標題 plt.savefig(desc_full + '/微信好友區(qū)域Top10' ) # 保存圖片
微信好友區(qū)域Top10 微信好友城市Top10 通過柱形圖展示,可以清晰看到我的好友主要分布在河南和上海,借此不難推測出我的工作地址以及戶籍所在地。
5.微信好友個性簽名情感分析及詞云圖展示 這里使用了常用的中文分詞庫jieba
,詞云圖的背景采用了萌萌噠小豬佩奇(′?·_·?)
sign_li = [] rule = re.compile('1fd+w*|[<>/=]' ) # 定義正則規(guī)則 for fri_info in we_friend[1:]: signature = fri_info['signature' ] if signature: sign_deal = signature.replace(' ' , '' ).replace(' ' , '' ).replace(' ' , '' ) .replace('span' , '' ).replace('class' , '' ).replace('emoji' , '' ) sign = rule.sub('' , sign_deal) sign_li.append(sign)
pwd_path = os.path.abspath(os.path.dirname(os.getcwd())) conf_path = os.path.join(pwd_path, 'conf/') comment_txt = '' back_img = plt.imread(conf_path + '/peiqi.jpg') cloud = WordCloud(font_path=conf_path + '/simhei.ttf', # 若是有中文的話,這句代碼必須添加,不然會出現(xiàn)方框,不出現(xiàn)漢字 background_color='white' , # 背景顏色 max_words=5000, # 詞云顯示的最大詞數(shù) mask=back_img, # 設置背景圖片 max_font_size=100, # 字體最大值 random_state=42, width=360, height=591, margin=2, # 設置圖片默認的大小,但是如果使用背景圖片的話,保存的圖片大小將會按照其大小保存,margin為詞語邊緣距離 ) for li in comment: comment_txt += ' '.join(jieba.cut(li, cut_all=False)) wc = cloud.generate(comment_txt) image_colors = ImageColorGenerator(back_img) plt.figure('wordc' ) plt.imshow(wc.recolor(color_func=image_colors)) wc.to_file(res_full + '好友個性簽名詞云圖.png')
好友個性簽名詞云圖 最初,只想做一個簡單的詞云圖,但是看到這個詞云圖中夢想、努力、專注、尊重、希望 這個幾個詞以后,感覺到我的好友生活態(tài)度還是蠻積極向上的,就想不如再做一個簡單的情感分析,說干就干。
sentimentslist = []for li in comment: if len (li) > 0 : s = SnowNLP(li) print (li, s.sentiments) sentimentslist.append(s.sentiments) fig1 = plt.figure('sentiment' ) plt.hist(sentimentslist, bins=np.arange(0 , 1 , 0.02 )) plt.savefig(res_full + '好友簽名情感分析' ) plt.show()
好友簽名情感分析 從圖中可以看出,正向情感要遠遠多于負向情感的數(shù)據(jù),積極樂觀的人往往都在一個圈子,果然是物以類聚,人以群分啊。
本文完整源碼