撤回我也能看到!教你用Python制作微信防撤回脚本

目录

一、之前解决方案二、分析msg信息三、确定消息类型四、锁定撤回的消息五、结语

一、之前解决方案

大概是这样:短时间内同一位好友发送了多条消息,当他随便撤回一条消息时,我们不能确定他到底撤回的到底是哪一条消息。只能猜他可能是撤回了最近的一条消息,然后将其他消息贴出来作为备选。代码如下:

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)

实际效果是这样:

撤回我也能看到!教你用Python制作微信防撤回脚本 

我这个强迫症简直受不了这么不确定的说法。

二、分析msg信息

要想确定撤回了哪一条信息,就必须先熟悉普通msg和撤回的msg里面都有哪些信息,他们的相同点和不同点。下面就来看看这两种情况下msg都是怎么样的,不需要仔细的看每一行,后面会作具体分析。

先是用机器人“小帮帮”发送过来的信息得到的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,下面是对比(高亮的部分是不同处,省略了部分相同内容。可以点击放大查看大图

撤回我也能看到!教你用Python制作微信防撤回脚本

现在来分析几条关键信息:

MsgId(与下面的NewMsgId同)
消息编号。这个很好理解,每条消息都是通过一个独一无二的编号来与其他消息区分,所以这两条消息的编号不同很正常。如果我们能拿到好友撤回消息的编号,也就能锁定这条消息了。
MsgType(与下面的Type同)
消息类型。如下图,左边是普通的对话消息,右边类似于系统提示消息。是不是可以根据这条信息来判断是不是有好友撤回了消息?

撤回我也能看到!教你用Python制作微信防撤回脚本

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制作微信防撤回脚本 

一个完美的微信防撤回脚本大功告成!

五、结语

Python有很多好用好玩的库,可以慢慢发掘。本期我们利用ItChat库编写了一个微信防撤回脚本。其实ItChat功能远远不止这些,它还可以处理微信群消息以及各种其他类型的消息,我们讲到的只是九牛一毛,更多的还要大家自己去探索。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容