一鍵生成微信個人專屬資料報告,瞭解你的微信社交歷史
一鍵生成微信個人專屬資料報告,瞭解你的微信社交歷史
簡介
你是否想過生成一份屬於你的微信個人資料報告,瞭解你的微信社交歷史。現在,我們基於python對微信好友進行全方位資料分析,包括:暱稱、性別、年齡、地區、備註名、個性簽名、頭像、群聊、公眾號等。
其中,在分析好友型別方面,主要統計出你的陌生人、星標好友、不讓他看我的朋友圈的好友、不看他的朋友圈的好友資料。在分析地區方面,主要統計所有好友在全國的分佈以及對好友數最多的省份進行進一步分析。在其他方面,統計出你的好友性別比例、猜出你最親密的好友,分析你的特殊好友,找出與你所在共同群聊數最多的好友資料,對你的好友個性簽名進行分析,對你的好友頭像進行分析,並進一步檢測出使用真人頭像的好友資料。
目前網上關於這方面的資料分析文章比較多,但是執行起來比較麻煩, 而本程式的執行十分簡單,只需要掃碼登入一步操作即可。
功能截圖
如何執行
# 跳轉到當前目錄 cd 目錄名 # 先解除安裝依賴庫 pip uninstall -y -r requirement.txt # 再重新安裝依賴庫 pip install -r requirement.txt # 開始執行 python generate_wx_data.py
如何打包成二進位制可執行檔案
# 安裝pyinstaller pip install pyinstaller # 跳轉到當前目錄 cd 目錄名 # 先解除安裝依賴庫 pip uninstall -y -r requirement.txt # 再重新安裝依賴庫 pip install -r requirement.txt # 更新 setuptools pip install --upgrade setuptools # 開始打包 pyinstaller generate_wx_data.py
編寫思路
- 首先,進行初始化,並根據不同作業系統,啟用微信機器人。
# 初始化所需資料夾 init_folders() # 啟動微信機器人,自動根據作業系統執行不同的指令 if('Windows' in system()): # Windows bot = Bot(cache_path=True) elif('Darwin' in system()): # MacOSX bot = Bot(cache_path=True) elif('Linux' in system()): # Linux bot = Bot(console_qr=2,cache_path=True) else: # 自行確定 print(u"無法識別你的作業系統型別,請自己設定") exit()
- 登入完微信後,開始獲取好友資料和群聊資料。
# 獲取所有好友 friends = bot.friends(update=False) # 獲取所有活躍群聊 groups = bot.groups()
- 共同所在群聊成員分析,依次對每個好友進行檢測。
def group_common_in(): # 獲取所有活躍的群聊 groups = bot.groups() # 每個好友與你相同的群聊個數 dict_common_in = {} # 遍歷所有好友,第0個為你自己,所以去掉 for x in friends[1:]: # 依次在每個群聊中搜索 for y in groups: # x在y中 if(x in y): # 獲取微信名稱 name = x.nick_name # 判斷是否有備註,有的話就使用備註 if(x.remark_name and x.remark_name != ''): name = x.remark_name # 增加計數 if(name in dict_common_in.keys()): dict_common_in[name] += 1 else: dict_common_in[name] = 1
- 獲取微信好友頭像,以便進一步分析。這裡下載頭像比較慢,所以採取多執行緒方式進行下載。在多執行緒中,使用佇列儲存我們的頭像url,不同執行緒從佇列中獲取頭像url,並下載到本地。
# 建立一個佇列,用於多執行緒下載頭像,提高下載速度 queue_head_image = Queue() # 將每個好友元素存入佇列中 # 如果為了方便除錯,可以僅僅插入幾個資料,friends[1:10] for user in friends: queue_head_image.put(user) # 啟動10個執行緒下載頭像 for i in range(1, 10): t = Thread(target=download_head_image,args=(i,)) t.start()
其中 download_head_image
的具體實現為:
# 下載好友頭像,此步驟消耗時間比較長 def download_head_image(thread_name): # 佇列不為空的情況 while(not queue_head_image.empty()): # 取出一個好友元素 user = queue_head_image.get() # 下載該好友頭像,並儲存到指定位置,生成一個15位數的隨機字串 random_file_name = ''.join([str(random.randint(0,9)) for x in range(15)]) user.get_avatar(save_path='image/' + random_file_name + '.jpg') # 輸出提示 print(u'執行緒%d:正在下載微信好友頭像資料,進度%d/%d,請耐心等待……' %(thread_name, len(friends)-queue_head_image.qsize(), len(friends)))
- 進行性別、地區統計,並將生產的html檔案儲存到本地。這裡沒什麼難度,所以就不詳細展開了。
# 分析好友性別比例 def sex_ratio(): # 初始化 male, female, other = 0, 0, 0 # 遍歷 for user in friends: if(user.sex == 1): male += 1 elif(user.sex == 2): female += 1 else: other += 1 name_list = ['男性', '女性', '未設定'] num_list = [male, female, other] pie = Pie("微信好友性別比例") pie.add("", name_list, num_list, is_label_show=True) pie.render('data/好友性別比例.html')
- 分析你認識的好友、最親密的人以及特殊好友。以特殊好友為例,我們將好友分為星標好友(很重要的人), 不讓他看我的朋友圈的好友, 不看他朋友圈的好友, 訊息置頂好友, 陌生人。這裡分類的依據是根據itchat中的
StarFriend
和ContactFlag
而來的。根據經驗可知,StarFriend
為1表示為星標好友,ContactFlag
為1和3表示好友,259和33027表示不讓他看我的朋友圈,65539和65537和66051表示不看他的朋友圈,65795表示兩項設定全禁止, 73731表示陌生人。
# 特殊好友分析 def analyze_special_friends(): # 星標好友(很重要的人), 不讓他看我的朋友圈的好友, 不看他朋友圈的好友, 訊息置頂好友, 陌生人 star_friends, hide_my_post_friends, hide_his_post_friends, sticky_on_top_friends, stranger_friends = 0, 0, 0, 0, 0 for user in friends: # 星標好友為1,為0表示非星標,不存在星標選項的為陌生人 if('StarFriend' in (user.raw).keys()): if((user.raw)['StarFriend'] == 1): star_friends += 1 else: stranger_friends += 1 # 好友型別及許可權:1和3好友,259和33027不讓他看我的朋友圈,65539和65537和66051不看他的朋友圈,65795兩項設定全禁止, 73731陌生人 if((user.raw)['ContactFlag'] in [259, 33027, 65795]): hide_my_post_friends += 1 if ((user.raw)['ContactFlag'] in [66051, 65537, 65539, 65795]): hide_his_post_friends += 1 # 訊息置頂好友為2051 if ((user.raw)['ContactFlag'] in [2051]): sticky_on_top_friends += 1 # 陌生人 if ((user.raw)['ContactFlag'] in [73731]): stranger_friends += 1 bar = Bar('特殊好友分析') bar.add(name='', x_axis=['星標', '不讓他看我朋友圈', '不看他朋友圈', '訊息置頂', '陌生人'], y_axis=[star_friends, hide_my_post_friends, hide_his_post_friends, sticky_on_top_friends, stranger_friends], legend_orient="vertical", legend_pos="left") bar.render('data/特殊好友分析.html')
- 對好友個性簽名進行分析,並繪製出詞語。這裡比較複雜,首先將個性簽名列表轉化為字串,呼叫nlp處理介面,對返回的資料進行過濾。同時,對短語進行分詞,過濾,詞頻統計操作。最後,使用pyechart進行繪製詞語圖。程式碼中註釋非常多,基本都能看懂,所以在此也無需再詳細展開了。
# 分析個性簽名 def analyze_signature(): # 個性簽名列表 data = [] for user in friends: # 清除簽名中的微信表情emoj,即<span class.*?</span> # 使用正則查詢並替換方式,user.signature為源文字,將<span class.*?</span>替換成空 new_signature = re.sub(re.compile(r"<span class.*?</span>", re.S), "", user.signature) # 只保留簽名為1行的資料,過濾為多行的簽名 if(len(new_signature.split('\n')) == 1): data.append(new_signature) # 將個性簽名列表轉為string data = '\n'.join(data) # 進行分詞處理,呼叫介面進行分詞 # 這裡不使用jieba或snownlp的原因是無法打包成exe檔案或者打包後文件非常大 postData = {'data':data, 'type':'exportword', 'arg':'', 'beforeSend':'undefined'} response = post('http://life.chacuo.net/convertexportword',data=postData) data = response.text.replace('{"status":1,"info":"ok","data":["', '') # 解碼 data = data.encode('utf-8').decode('unicode_escape') # 將返回的分詞結果json字串轉化為python物件,並做一些處理 data = data.split("=====================================")[0] # 將分詞結果轉化為list,根據分詞結果,可以知道以2個空格為分隔符 data = data.split('') # 對分詞結果資料進行去除一些無意義的詞操作 stop_words_list = [',', ',', '、', 'the', 'a', 'is', '…', '·', 'э', 'д', 'э', 'м', 'ж', 'и', 'л', 'т', 'ы', 'н', 'з', 'м', '…', '…', '…', '…', '…', '、', '.', '。', '!', '!', ':', ':', '~', '|', '▽', '`', 'ノ', '♪', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\'', '‘', '’', '“', '”', '的', '了', '是', '你', '我', '他', '她','=', '\r', '\n', '\r\n', '\t', '以下關鍵詞', '[', ']', '{', '}', '(', ')', '(', ')', 'span', '<', '>', 'class', 'html', '?', '就', '於', '下', '在', '嗎', '嗯'] tmp_data = [] for word in data: if(word not in stop_words_list): tmp_data.append(word) data = tmp_data # 進行詞頻統計,結果存入字典signature_dict中 signature_dict = {} for index, word in enumerate(data): print(u'正在統計好友簽名資料,進度%d/%d,請耐心等待……' % (index + 1, len(data))) if(word in signature_dict.keys()): signature_dict[word] += 1 else: signature_dict[word] = 1 # 開始繪製詞雲 name = [x for x in signature_dict.keys()] value = [x for x in signature_dict.values()] wordcloud = WordCloud('微信好友個性簽名詞雲圖') wordcloud.add("", name, value, shape='star', word_size_range=[1,100]) wordcloud.render('data/好友個性簽名詞雲.html')
- 拼接所有好友頭像,這裡使用到PIL的影象處理功能,首先對頭像個數進行統計,自適應生成矩形圖片。由於我們知道微信頭像尺寸為640 * 640,所以處理起來就很方便了。
# 拼接所有微信好友頭像 def merge_head_image(): # 拼接頭像 pics = listdir('image')# 得到user目錄下的所有檔案,即各個好友頭像 numPic = len(pics) eachsize = int(math.sqrt(float(640 * 640) / numPic))# 先圈定每個正方形小頭像的邊長,如果嫌小可以加大 numrow = int(640 / eachsize) numcol = int(numPic / numrow)# 向下取整 toImage = Image.new('RGB', (eachsize * numrow, eachsize * numcol))# 先生成頭像集模板 x = 0# 小頭像拼接時的左上角橫座標 y = 0# 小頭像拼接時的左上角縱座標 for index, i in enumerate(pics): print(u'正在拼接微信好友頭像資料,進度%d/%d,請耐心等待……' % (index + 1, len(pics))) try: # 開啟圖片 img = Image.open('image/' + i) except IOError: print(u'Error: 沒有找到檔案或讀取檔案失敗') else: # 縮小圖片 img = img.resize((eachsize, eachsize), Image.ANTIALIAS) # 拼接圖片 toImage.paste(img, (x * eachsize, y * eachsize)) x += 1 if x == numrow: x = 0 y += 1 toImage.save('data/拼接' + ".jpg")
- 檢測使用人臉作為頭像的好友數量,這裡使用到opencv的人臉檢測功能,使用opencv預設的模型進行檢測。首先載入圖片,並進行灰度處理,最後載入人臉識別模型進行檢測,若檢測到臉數大於0,則說明存在。同時要注意的是,對錯誤的頭像要進行捨棄操作。
# 檢測使用真實人臉的好友個數 def detect_human_face(): # 得到user目錄下的所有檔名稱,即各個好友頭像 pics = listdir('image') # 使用人臉的頭像個數 count_face_image = 0 # 儲存使用人臉的頭像的檔名 list_name_face_image = [] # 載入人臉識別模型 face_cascade = CascadeClassifier('model/haarcascade_frontalface_default.xml') for index, file_name in enumerate(pics): print(u'正在進行人臉識別,進度%d/%d,請耐心等待……' % (index+1, len(pics))) # 讀取圖片 img = imread('image/' + file_name) # 檢測圖片是否讀取成功,失敗則跳過 if img is None: continue # 對圖片進行灰度處理 gray = cvtColor(img, COLOR_BGR2GRAY) # 進行實際的人臉檢測,傳遞引數是scaleFactor和minNeighbor,分別表示人臉檢測過程中每次迭代時圖 faces = face_cascade.detectMultiScale(gray, 1.3, 5) if (len(faces) > 0): count_face_image += 1 list_name_face_image.append(file_name) print(u'使用人臉的頭像%d/%d' %(count_face_image,len(pics)))
- 所有資料統計完後,我們生產一個總的html網頁檔案,方便我們直接檢視。
# 生成一個html檔案,並儲存到檔案file_name中 def generate_html(file_name): with open(file_name, 'w', encoding='utf-8') as f: data = ''' <meta http-equiv='Content-Type' content='text/html; charset=utf-8'> <meta charset="UTF-8"> <title>一鍵生成微信個人專屬資料報告(瞭解你的微信社交歷史)</title> <meta name='keywords' content='微信個人資料'> <meta name='description' content=''> <iframe name="iframe1" marginwidth=0 marginheight=0 width=100% height=60% src="data/好友地區分佈.html" frameborder=0></iframe> <iframe name="iframe2" marginwidth=0 marginheight=0 width=100% height=60% src="data/某省好友地區分佈.html" frameborder=0></iframe> <iframe name="iframe3" marginwidth=0 marginheight=0 width=100% height=60% src="data/好友性別比例.html" frameborder=0></iframe> <iframe name="iframe4" marginwidth=0 marginheight=0 width=100% height=60% src="data/你認識的好友比例.html" frameborder=0></iframe> <iframe name="iframe5" marginwidth=0 marginheight=0 width=100% height=60% src="data/你最親密的人.html" frameborder=0></iframe> <iframe name="iframe6" marginwidth=0 marginheight=0 width=100% height=60% src="data/特殊好友分析.html" frameborder=0></iframe> <iframe name="iframe7" marginwidth=0 marginheight=0 width=100% height=60% src="data/共同所在群聊分析.html" frameborder=0></iframe> <iframe name="iframe8" marginwidth=0 marginheight=0 width=100% height=60% src="data/好友個性簽名詞雲.html" frameborder=0></iframe> <iframe name="iframe9" marginwidth=0 marginheight=0 width=100% height=60% src="data/微信好友頭像拼接圖.html" frameborder=0></iframe> <iframe name="iframe10" marginwidth=0 marginheight=0 width=100% height=60% src="data/使用人臉的微信好友頭像拼接圖.html" frameborder=0></iframe> ''' f.write(data)
補充
完整版原始碼存放在 github 上,有需要的可以下載
專案持續更新,歡迎您 star本專案