用 Python 分析了所有微信好友,發現了一個祕密...

原文鏈接:https://blog.csdn.net/hejjunlin/article/details/92873179

 

 

640?wx_fmt=jpeg


 

Illustrations by Evgenij Kungur 文/ Python攻城獅

 

最近研究了一下itchat和matplotlib,目前實現了對微信好友頭像、性別、區域、個性簽名的採集及展示。

本文就來詳細介紹一下這個庫的用法和一些核心邏輯實現。

1.微信登錄

import itchatitchat.auto_login(hotReload=True)itchat.dump_login_status()

itchat.auto_login(hotReload=True)
itchat.dump_login_status()
we_friend = itchat.get_friends(update=True)[:]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 += 1for 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 * 100woman_ratio = int(woman)/total * 100other_ratio = int(other)/total * 100plt.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()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()

640?wx_fmt=png

微信好友性別比例

作爲一個碼農、程序猿,還能有這麼多女性好友實屬不易啊。敏感的我,看了這個比例深深地感覺到了不安,(此圖女朋友不可見)另外,怎麼還有一些未知生物的存在…


友情提醒:matplotlib中文亂碼這個問題一直存在,這裏記錄下如何解決matplotlib中文亂碼

import matplotlibprint(matplotlib.matplotlib_fname())    # 查看路徑
print(matplotlib.matplotlib_fname())    # 查看路徑
font.family        : sans-seriffont.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.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

把.cache下面的matplotlib文件夾刪除。

$ rm -rf matplotlib

3.微信好友頭像

這裏其實看過我之前文章的應該知道,其實頭像的拼接主要分爲兩部分

import osnum = 0pwd_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

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))   # 創建640*640px的大圖x = 0y = 0for 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 += 1image.save(desc_full + "/好友頭像拼接圖.jpg")# 算出每張圖片的大小多少合適
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")

密集恐懼症患者請忽略!!!

640?wx_fmt=jpeg

好友頭像拼接

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] += 1for 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。

# 區域Top10prov_dict_top10 = sorted(prov_dict.items(), key=lambda x: x[1], reverse=True)[0:10]# 城市Top10city_dict_top10 = sorted(city_dict.items(), key=lambda y: y[1], reverse=True)[0:10]
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')  # 保存圖片
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')  # 保存圖片

640?wx_fmt=png

微信好友區域Top10

640?wx_fmt=png

微信好友城市Top10

通過柱形圖展示,可以清晰看到我的好友主要分佈在河南和上海,藉此不難推測出我的工作地址以及戶籍所在地。

5.微信好友個性簽名情感分析及詞雲圖展示

這裏使用了常用的中文分詞庫jieba,詞雲圖的背景採用了萌萌噠小豬佩奇(´๑•_•๑)

sign_li = []rule = re.compile("1fd+w*|[<>/=]")    # 定義正則規則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)"1fd+w*|[<>/=]")    # 定義正則規則
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',  # 若是有中文的話,這句代碼必須添加,不然會出現方框,不出現漢字                  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')
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')

640?wx_fmt=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()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()

640?wx_fmt=png

好友簽名情感分析

從圖中可以看出,正向情感要遠遠多於負向情感的數據,積極樂觀的人往往都在一個圈子,果然是物以類聚,人以羣分啊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章