手把手教你用itchat統計好友資訊,瞭解一下?
初學Python的時候,就寫過一篇利用Python的第三方庫進行好友頭像拼接, itchat
itchat庫初探--微信好友全頭像的拼接,最近又研究了下itchat和matplotlib,目前實現了對微信好友頭像、性別、區域、個性簽名的採集及展示。
本文就來詳細介紹一下這個庫的用法和一些核心邏輯實現。
1.微信登入
- 三行程式碼實現登入,為了避免我們頻繁掃描二維碼登入,這裡我們加入
hotReload=True
import itchat itchat.auto_login(hotReload=True) itchat.dump_login_status() 複製程式碼
- 好友資訊獲取
we_friend = itchat.get_friends(update=True)[:] 複製程式碼
這裡的 we_friend
是好友的資訊的列表,每一個好友字典的 key 如下表
key | 備註 |
---|---|
UserName | 微信系統內的使用者編碼標識 |
NickName | 好友暱稱 |
Sex | 性別 |
Province | 省份 |
City | 城市 |
HeadImgUrl | 微信系統內的頭像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 複製程式碼
統計出男生、女生的以及總人數後,佔比自然而然就出來了,為了更好的展示男女比例,我們以餅圖展示。
- 繪製餅圖
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() 複製程式碼

作為一個碼農、程式猿,還能有這麼多女性好友實屬不易啊。敏感的我,看了這個比例深深地感覺到了不安,(
此圖女朋友不可見
)另外,怎麼還有一些未知生物的存在...
友情提醒:matplotlib中文亂碼這個問題一直存在,這裡記錄下 如何解決matplotlib中文亂碼
- 準備好想要使用的中文字型,這裡我用的是 SimHei ,附下載地址:中文字型下載
- 找到matplotlib的檔案位置
import matplotlib print(matplotlib.matplotlib_fname())# 檢視路徑 複製程式碼
-
進入上方列印的路徑
-
把剛才下載的字型檔案解壓放入
/usr/local/lib/python3.5/dist-packages/matplotlib/mpl-data/fonts/ttf
目錄 -
返回上級目錄,修改matplotlibrc檔案,取消相關注釋,並在
font.serif
加入剛才下載的字型
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 複製程式碼
- 刪除matplotlib快取。
在terminal中:cd ~/.cache/matplotlib 把.cache下面的matplotlib資料夾刪除。 $ rm -rf matplotlib 複製程式碼
3.微信好友頭像
這裡其實看過我之前文章的應該知道,其實頭像的拼接主要分為兩部分
- 1.採集所有好友頭像儲存本地,
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 複製程式碼
- 2.對所有頭像進行拼接
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))# 建立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.微信好友地區分佈
-- 獲取區域及城市
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 複製程式碼
由於城市太多,我們取好友數量排名前十的城市及區域進行展示,感興趣的可以稍微改下程式碼,就可以展示所有區域人數。
排序這裡我用了Python的 sorted()
函式,列表的每個元素都為二維元組, key
引數傳入了一個 lambda函式
,其x就代表列表裡的每一個元素,然後分別利用索引返回元素內的第一個和第二個元素,這就代表了 sorted()
函式利用哪一個元素進行排列。而 reverse
決定是正序還是倒序,預設為False。
# 區域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 = [], []# 省會名 + 數量 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('省會好友人數')# 設定縱座標標籤 prov_title = '微信好友區域Top10' plt.title(prov_title)# 設定標題 plt.savefig(desc_full + '/微信好友區域Top10')# 儲存圖片 複製程式碼


通過柱形圖展示,可以清晰看到我的好友主要分佈在河南和上海,藉此不難推測出我的工作地址以及戶籍所在地。
5.微信好友個性簽名情感分析及詞雲圖展示
這裡使用了常用的中文分詞庫 jieba
,詞雲圖的背景採用了萌萌大小豬佩奇(´๑•_•๑)
- 分詞
sign_li = [] rule = re.compile("1f\d+\w*|[<>/=]")# 定義正則規則 for fri_info in we_friend[1:]: signature = fri_info['signature'] if signature: sign_deal = signature.replace('\n', '').replace('\t', '').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',# 若是有中文的話,這句程式碼必須新增,不然會出現方框,不出現漢字 background_color="white",# 背景顏色 max_words=5000,# 詞雲顯示的最大詞數 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') 複製程式碼

最初,只想做一個簡單的詞雲圖,但是看到這個詞雲圖中 夢想、努力、專注、尊重、希望 這個幾個詞以後,感覺到我的好友生活態度還是蠻積極向上的,就想不如再做一個簡單的情感分析,說幹就幹。
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() 複製程式碼

從圖中可以看出,正向情感要遠遠多於負向情感的資料,積極樂觀的人往往都在一個圈子,果然是物以類聚,人以群分啊。
完整程式碼以上傳 Github ,期待您的Star。