【Python寫微信防撤回腳本】完結續 鎖定被撤回的消息

這個系列文章裏曾經說過,若是好友短期發送多條消息而後撤回會難以判斷究竟撤回的是哪條信息,只能靠猜。後來我以爲「猜」這個事情特別不Pythonic,研究一段時間後找到了解決方案,不得不驚歎ItChat真的好強大。html

以前的解決方案

以前的不能肯定的狀況大概是這樣:短期內同一位好友發送了多條消息,當他隨便撤回一條消息時,咱們不能肯定他到底撤回的究竟是哪一條消息。只能猜他多是撤回了最近的一條消息,而後將其餘消息貼出來做爲備選。代碼以下:python

target_msg_pattern = '"{}" 撤回了一條消息'.format(sender_name)
if content == target_msg_pattern:
    return_msg = '【{}】撤回了一條消息:\n'.format(sender_name)
    if len(log[sender_name].items()) == 0:
        return_msg = '緩存信息列表爲空!'
    else:
        return_msg += log[sender_name].items()[-1][-1] + '\n'
        if len(log[sender_name].items()) > 1:
            msgs = [msg for timestamp, msg in log[sender_name].items()[:-1]]
            return_msg += '也有多是下列信息中的某一條:\n' + '\n'.join(msgs)
複製代碼

實際效果是這樣:git

我這個強迫症簡直受不了這麼不肯定的說法。github

分析msg信息

要想肯定撤回了哪一條信息,就必須先熟悉普通msg和撤回的msg裏面都有哪些信息,他們的相同點和不一樣點。下面就來看看這兩種狀況下msg都是怎麼樣的,不須要仔細的看每一行,後面會做具體分析。web

先是用機器人「小幫幫」發送過來的信息獲得的msg信息:緩存

{
	'MsgId': '2018511155698964390',
	'FromUserName': '@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3',
	'ToUserName': '@**********c2e61fdb47b5c241553a2f',
	'MsgType': 1,
	'Content': 'msg裏面到底有什麼?',
	'Status': 3,
	'ImgStatus': 1,
	'CreateTime': 1578069291,
	'VoiceLength': 0,
	'PlayLength': 0,
	'FileName': '',
	'FileSize': '',
	'MediaId': '',
	'Url': '',
	'AppMsgType': 0,
	'StatusNotifyCode': 0,
	'StatusNotifyUserName': '',
	'RecommendInfo': {
		'UserName': '',
		'NickName': '',
		'QQNum': 0,
		'Province': '',
		'City': '',
		'Content': '',
		'Signature': '',
		'Alias': '',
		'Scene': 0,
		'VerifyFlag': 0,
		'AttrStatus': 0,
		'Sex': 0,
		'Ticket': '',
		'OpCode': 0
	},
	'ForwardFlag': 0,
	'AppInfo': {
		'AppID': '',
		'Type': 0
	},
	'HasProductId': 0,
	'Ticket': '',
	'ImgHeight': 0,
	'ImgWidth': 0,
	'SubMsgType': 0,
	'NewMsgId': 2018511155698964390,
	'OriContent': '',
	'EncryFileName': '',
	'User': < User: {
		'MemberList': < ContactList: [] > ,
		'Uin': 0,
		'UserName': '@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3',
		'NickName': '小幫幫',
		'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=699837854&username=@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3&skey=@crypt_****c00c_92668c8ba7d285c221a85e**********',
		'ContactFlag': 2049,
		'MemberCount': 0,
		'RemarkName': '小幫幫',
		'HideInputBarFlag': 0,
		'Sex': 2,
		'Signature': '',
		'VerifyFlag': 0,
		'OwnerUin': 0,
		'PYInitial': 'XBB',
		'PYQuanPin': 'xiaobangbang',
		'RemarkPYInitial': 'XBB',
		'RemarkPYQuanPin': 'xiaobangbang',
		'StarFriend': 0,
		'AppAccountFlag': 0,
		'Statues': 0,
		'AttrStatus': 33658937,
		'Province': '浙江',
		'City': '台州',
		'Alias': '',
		'SnsFlag': 17,
		'UniFriend': 0,
		'DisplayName': '',
		'ChatRoomId': 0,
		'KeyWord': '',
		'EncryChatRoomId': '',
		'IsOwner': 0
	} > ,
	'Type': 'Text',
	'Text': 'msg裏面到底有什麼?'
}
複製代碼

下面是機器人撤回剛纔的信息獲得的msg信息:微信

{
	'MsgId': '4056955577161654067',
	'FromUserName': '@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3',
	'ToUserName': '@**********c2e61fdb47b5c241553a2f',
	'MsgType': 10002,
	'Content': '<sysmsg type="revokemsg"><revokemsg><session>wxid_4gngrr04aqjn21</session><oldmsgid>1123721956</oldmsgid><msgid>2018511155698964390</msgid><replacemsg><![CDATA["小幫幫" 撤回了一條消息]]></replacemsg></revokemsg></sysmsg>',
	'Status': 4,
	'ImgStatus': 1,
	'CreateTime': 1578069381,
	'VoiceLength': 0,
	'PlayLength': 0,
	'FileName': '',
	'FileSize': '',
	'MediaId': '',
	'Url': '',
	'AppMsgType': 0,
	'StatusNotifyCode': 0,
	'StatusNotifyUserName': '',
	'RecommendInfo': {
		'UserName': '',
		'NickName': '',
		'QQNum': 0,
		'Province': '',
		'City': '',
		'Content': '',
		'Signature': '',
		'Alias': '',
		'Scene': 0,
		'VerifyFlag': 0,
		'AttrStatus': 0,
		'Sex': 0,
		'Ticket': '',
		'OpCode': 0
	},
	'ForwardFlag': 0,
	'AppInfo': {
		'AppID': '',
		'Type': 0
	},
	'HasProductId': 0,
	'Ticket': '',
	'ImgHeight': 0,
	'ImgWidth': 0,
	'SubMsgType': 0,
	'NewMsgId': 4056955577161654067,
	'OriContent': '',
	'EncryFileName': '',
	'User': < User: {
		'MemberList': < ContactList: [] > ,
		'Uin': 0,
		'UserName': '@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3',
		'NickName': '小幫幫',
		'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=699837854&username=@**********f511363f8200853d724137bb31236a7ea81e5183cc06cb4ec978e3&skey=@crypt_****c00c_92668c8ba7d285c221a85e**********',
		'ContactFlag': 2049,
		'MemberCount': 0,
		'RemarkName': '小幫幫',
		'HideInputBarFlag': 0,
		'Sex': 2,
		'Signature': '',
		'VerifyFlag': 0,
		'OwnerUin': 0,
		'PYInitial': 'XBB',
		'PYQuanPin': 'xiaobangbang',
		'RemarkPYInitial': 'XBB',
		'RemarkPYQuanPin': 'xiaobangbang',
		'StarFriend': 0,
		'AppAccountFlag': 0,
		'Statues': 0,
		'AttrStatus': 33658937,
		'Province': '浙江',
		'City': '台州',
		'Alias': '',
		'SnsFlag': 17,
		'UniFriend': 0,
		'DisplayName': '',
		'ChatRoomId': 0,
		'KeyWord': '',
		'EncryChatRoomId': '',
		'IsOwner': 0
	} > ,
	'Type': 'Note',
	'Text': '"小幫幫" 撤回了一條消息'
}
複製代碼

獲得了兩種類型的msg,下面是對比(高亮的部分是不一樣處,省略了部分相同內容。能夠點擊放大查看大圖):session

如今來分析幾條關鍵信息:併發

  • MsgId(與下面的NewMsgId同)ide

    消息編號。這個很好理解,每條消息都是經過一個獨一無二的編號來與其餘消息區分,因此這兩條消息的編號不一樣很正常。若是咱們能拿到好友撤回消息的編號,也就能鎖定這條消息了。

  • MsgType(與下面的Type同)

    消息類型。以下圖,左邊是普通的對話消息,右邊相似於系統提示消息。是否是能夠根據這條信息來判斷是否是有好友撤回了消息?

  • Content

    消息內容,注意與下面的Text區分,這兩種消息類型在內容上最大的區別可能就在這裏了。

    來看一下撤回消息的Content是怎麼樣的(爲了便於查看,已經通過格式化):

    <sysmsg type="revokemsg">
        <revokemsg>
            <session>wxid_4gngrr04aqjn21</session>
            <oldmsgid>1123721956</oldmsgid>
            <msgid>2018511155698964390</msgid>
            <replacemsg><![CDATA["小幫幫" 撤回了一條消息]]></replacemsg>
        </revokemsg>
    </sysmsg>
    複製代碼

    一眼就能發現關鍵點:撤回的那條消息屬於系統消息(sysmsg),類型是撤回消息(revokemsg),對應的消息編號是2018511155698964390

    細心的讀者已經發現,這個消息編號正好就是左邊那條消息的編號。

    經過這個推理,猜想Content字段是系統內部傳輸的內容,而Text字段則是用戶看到的內容。

肯定消息類型

根據上述分析,有三個地方幫助肯定收到的某條信息是不是撤回的消息:

  1. MsgType

    1就是普通消息,是10002則可能爲撤回消息。

  2. Content

    若是Content裏有包含type="revokemsg"則可能爲撤回消息,不然不是撤回消息。

  3. Type

    Text就是普通消息,是Note則可能爲撤回消息。

精確起見,消息還要同時知足上面三種狀況纔可認定爲撤回消息。

鎖定撤回的消息

因爲要鎖定撤回消息必需要MsgId才能肯定,因此在存儲臨時消息時須要加上這一字段。

log[sender_name][cur_timestamp] = msg['MsgId'] + '|||' + content
複製代碼

爲了簡化數據複雜度,我經過分隔符|||直接把MsgId加在前面。

因而,鎖定併發送撤回消息的代碼就時這樣:

content = str(msg['Text'])
revoke_info = msg['Content']
print('{}, {} 發來消息: {}'.format(formatted_timestamp, sender_name, content))
target_msg_pattern = '"{}" 撤回了一條消息'.format(sender_name)
if target_msg_pattern == content and msg['Type'] == 'Note' and str(msg['MsgType']) == '10002' and 'type="revokemsg"' in revoke_info:
    return_msg = ''
    return_msg_head = '{},【{}】撤回了一條消息:\n'.format(formatted_timestamp, sender_name)
    revoke_msg_id = revoke_info.split('<msgid>')[-1].split('</msgid>')[0]
    for _, value in log[sender_name].items():
        if value.split('|||')[0] == revoke_msg_id:
            return_msg = value.split('|||')[1]
    if return_msg == '':
        return_msg = '緩存信息列表爲空!'
    return_msg = return_msg_head + return_msg
    print(return_msg)
    itchat.send_msg(return_msg, 'filehelper')
複製代碼

測試一下,爲便於查看,將撤回提醒直接發給機器人「小幫幫」(掘金上不會上傳動圖,須要看動圖版本的能夠到這裏):

一個完美的微信防撤回腳本大功告成!

結語

系列結語 Python有不少好用好玩的庫,能夠慢慢發掘。本期咱們利用ItChat庫編寫了一個微信防撤回腳本。其實ItChat功能遠遠不止這些,它還能夠處理微信羣消息以及各類其餘類型的消息,咱們講到的只是九牛一毛,更多的還要你們本身去探索。

這個系列就到此爲止了,若是有想要了解交流的能夠在公衆號主頁聯繫我,這個系列的代碼在這裏:

https://github.com/TitusWongCN/AntiInfoWithdrawal
複製代碼

你們有什麼想了解的,或者有什麼想作的也能夠在文章後面留言,後面說不定就會作了哦~

後記

無論寫什麼,但願能跟更多人溝通,有問題或者需求隨時歡迎交流。

我全部的項目源碼都會放在下面的github倉庫裏面,有須要能夠參考,有問題歡迎指正,謝謝!

https://github.com/TitusWongCN/
複製代碼

【Python寫微信防撤回腳本】往期推薦:

第一期:【Python寫微信防撤回腳本】01 熟悉ItChat庫

第二期:【Python寫微信防撤回腳本】02 接收記錄聊天信息

第三期:【Python寫微信防撤回腳本】03 獲取撤回信息並整理

第四期:【Python寫微信防撤回腳本】04完結 發送被撤回消息

下面是個人公衆號,有興趣能夠掃一下:

相關文章
相關標籤/搜索