天天看點

使用itchat監控微信消息,從此不再為撤回煩惱

強大的Itchat

itchat是一個開源的微信個人号接口,使用python封裝接入微信網頁版接口,通過調用itchat來登入微信網頁版收發消息。

項目簡介 - itchat

掌握itchat之後,隻要你有興趣可以随意開發自己的專屬微信網頁版用戶端。目前比較流行的就是利用它來找回他人撤回的微信消息,和設定自動聊天機器人

撤回的微信消息

找回邏輯非常簡單,對方撤回消息的時候,我們會收到一個

[note]

類型的推送消息,裡面包含了撤回的消息id

msg_id

。我們可以對所有收到的消息進行監控并暫時儲存,當收到撤回的通知時從存儲中找到這條消息記錄通過某種方式告知自己。簡單歸納如下

  1. 暫存微信消息,以消息ID作為主鍵,建議直接存記憶體裡。如果是圖檔等其他資源,需要下載下傳到一個臨時目錄
  2. 監控撤回通知。通過撤回消息關鍵字找到撤回的消息id,到暫存的曆史消息裡找到對應記錄,通過檔案轉發助手直接發送到手機用戶端。如果是圖檔等資源,則從臨時目錄找到對應檔案發送
  3. 因為微信消息撤回時限為2分鐘,是以可以把2分鐘之前的所有曆史記錄删除,以節省記憶體(或者儲存到其他地方)

前提是2分鐘内不會收到太多消息以至記憶體耗盡

代碼示例

import os
import re
import shutil
import time
import itchat
from itchat.content import *

# 說明:可以撤回的有文本文字、語音、視訊、圖檔、位置、名片、分享、附件
# {msg_id:(msg_from,msg_to,msg_time,msg_time_rec,msg_type,msg_content,msg_share_url)}
msg_dict = {}

# 檔案存儲臨時目錄

# rev_tmp_dir = "/home/wechat"
rev_tmp_dir = "F:\private files\wechat\\"
qr_dir = "F:\\qrcode.png"

if not os.path.exists(rev_tmp_dir):
    os.mkdir(rev_tmp_dir)

# 表情有一個問題 | 接受資訊和接受note的msg_id不一緻 巧合解決方案
#face_bug = None

# 将接收到的消息存放在字典中,當接收到新消息時對字典中逾時的消息進行清理 | 不接受不具有撤回功能的資訊
# [TEXT, PICTURE, MAP, CARD, SHARING, RECORDING, ATTACHMENT, VIDEO, FRIENDS, NOTE]
@ itchat.msg_register([TEXT, PICTURE, MAP, CARD, SHARING, RECORDING, ATTACHMENT, VIDEO])
def handler_receive_msg(msg):
    # 擷取的是本地時間戳并格式化本地時間戳 e: 2017-04-21 21:30:08
    msg_time_rec = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    # 消息ID
    msg_id = msg[\'MsgId\']
    #print(msg_id)
    # 消息時間
    msg_time = msg[\'CreateTime\']
    # 消息發送人昵稱 | 這裡也可以使用RemarkName備注 但是自己或者沒有備注的人為None
    msg_from = (itchat.search_friends(userName=msg[\'FromUserName\']))["NickName"]
    #print(msg_from)
    # 消息内容
    msg_content = None
    # 分享的連結
    msg_share_url = None

    if msg[\'Type\'] == \'Text\' or msg[\'Type\'] == \'Friends\':
        msg_content = msg[\'Text\']
    elif msg[\'Type\'] == \'Recording\' or msg[\'Type\'] == \'Attachment\' or msg[\'Type\'] == \'Video\' or msg[\'Type\'] == \'Picture\':
        msg_content = r"" + msg[\'FileName\']
        # 儲存檔案
        msg[\'Text\'](rev_tmp_dir + msg[\'FileName\'])
    elif msg[\'Type\'] == \'Card\':
        msg_content = msg[\'RecommendInfo\'][\'NickName\'] + r" 的名片"
        # itchat.send(msg_content, toUserName=\'filehelper\')
    elif msg[\'Type\'] == \'Map\':
        x, y, location = re.search(\'<location x="(.*?)" y="(.*?)".*label="(.*?)".*\', msg[\'OriContent\']).group(1, 2, 3)
        if location is None:
            msg_content = r"緯度->" + x.__str__() + " 經度->" + y.__str__()
        else:
            msg_content = r"" + location
    elif msg[\'Type\'] == \'Sharing\':
        msg_content = msg[\'Text\']
        msg_share_url = msg[\'Url\']
    # 更新字典
    msg_dict.update({
        msg_id: {
            "msg_from": msg_from, "msg_time": msg_time, "msg_time_rec": msg_time_rec,
            "msg_type": msg["Type"],
            "msg_content": msg_content, "msg_share_url": msg_share_url
        }
    })
    # 删除過期記錄
    for mid in list(msg_dict.keys()):
        if (msg_dict[mid].get(\'msg_time\') < time.time()-120):
            # 删除記錄,以及對應的檔案(略)
            del msg_dict[mid]
        else:
            break

 # 收到note通知類消息,判斷是不是撤回并進行相應操作
@ itchat.msg_register([NOTE])
def send_msg_helper(msg):
    # 比對撤回消息
    if re.search(r"\<\!\[CDATA\[.*撤回了一條消息\]\]\>", msg[\'Content\']) is not None:
        # 擷取消息的id
        old_msg_id = re.search("<msgid>(.*?)</msgid>", msg[\'Content\']).group(1)
        print("發現撤回消息 " + old_msg_id)
        old_msg = msg_dict.get(old_msg_id, {})
        # print(old_msg)
        msg_body = "[撤回]" + " " + old_msg.get(\'msg_from\') + " " + old_msg.get(\'msg_time_rec\') + "\n" + old_msg.get(\'msg_content\')
        # 如果是分享
        if old_msg[\'msg_type\'] == "Sharing":
            msg_body += old_msg.get(\'msg_share_url\')
        # 将撤回消息發送到檔案助手
        itchat.send(msg_body, toUserName=\'filehelper\')
        # 有檔案的話也要将檔案發送回去
        if old_msg["msg_type"] == "Picture" or old_msg["msg_type"] == "Recording" or old_msg["msg_type"] == "Video" or old_msg["msg_type"] == "Attachment":
            file = \'@%s@%s\' % (\'img\' if msg[\'Type\'] == \'Picture\' else \'fil\', rev_tmp_dir + old_msg[\'msg_content\'])
            itchat.send(msg=file, toUserName=\'filehelper\')

if __name__ == \'__main__\':
    # 打開 hotReload 短時間内可自動重新登入
    # 指令行檢視二維碼使用 enableCmdQR=True,關閉則會調用系統的檔案檢視指令(win 使用 open, linux 使用 xdg-open,需要yum install xdg-utils)
    itchat.auto_login(hotReload=True, enableCmdQR=1)
    itchat.run()

           

其他應用

  • 聊天機器人自動回複
  • 發送定時消息
  • 鬥圖(調用圖像識别api)
  • 聊天記錄備份,分析
  • 微信好友資料分析