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


Posted in Python onJune 11, 2021

一、之前解决方案

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

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功能远远不止这些,它还可以处理微信群消息以及各种其他类型的消息,我们讲到的只是九牛一毛,更多的还要大家自己去探索。

到此这篇关于撤回我也能看到!教你用Python制作微信防撤回脚本的文章就介绍到这了,更多相关Python微信防撤回脚本内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python Web框架Flask下网站开发入门实例
Feb 08 Python
Python实现windows下模拟按键和鼠标点击的方法
Mar 13 Python
Python3.6 Schedule模块定时任务(实例讲解)
Nov 09 Python
python如何通过twisted实现数据库异步插入
Mar 20 Python
Python操作rabbitMQ的示例代码
Mar 19 Python
python从入门到精通 windows安装python图文教程
May 18 Python
python3获取当前目录的实现方法
Jul 29 Python
python-视频分帧&amp;多帧合成视频实例
Dec 10 Python
python实现学生通讯录管理系统
Feb 25 Python
Keras在mnist上的CNN实践,并且自定义loss函数曲线图操作
May 25 Python
基于Python实现nc批量转tif格式
Aug 14 Python
Python pyecharts案例超市4年数据可视化分析
Aug 14 Python
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
matplotlib如何设置坐标轴刻度的个数及标签的方法总结
PyQt5结合QtDesigner实现文本框读写操作
Python中seaborn库之countplot的数据可视化使用
You might like
PHP-CGI进程CPU 100% 与 file_get_contents 函数的关系分析
2011/08/15 PHP
PHP中mysql_field_type()函数用法
2014/11/24 PHP
WordPress自定义时间显示格式
2015/03/27 PHP
laravel model 两表联查示例
2019/10/24 PHP
重定向实现代码
2006/11/20 Javascript
关于使用 jBox 对话框的提交不能弹出问题解决方法
2012/11/07 Javascript
JavaScript不刷新实现浏览器的前进后退功能
2014/11/05 Javascript
node.js中的querystring.parse方法使用说明
2014/12/10 Javascript
JavaScript列表框listbox全选和反选的实现方法
2015/03/18 Javascript
原生javascript实现匀速运动动画效果
2016/02/26 Javascript
用Vue.js实现监听属性的变化
2016/11/17 Javascript
jQuery操作css样式
2017/05/15 jQuery
JavaScript实现一个空中避难的小游戏
2017/06/06 Javascript
浅谈node中的cluster集群
2018/06/02 Javascript
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
vue中监听路由参数的变化及方法
2019/12/06 Javascript
javascript开发实现贪吃蛇游戏
2020/07/31 Javascript
解决vue中使用less/sass及使用中遇到无效的问题
2020/10/24 Javascript
在Python中利用Pandas库处理大数据的简单介绍
2015/04/07 Python
python 文件转成16进制数组的实例
2018/07/09 Python
Python使用装饰器模拟用户登陆验证功能示例
2018/08/24 Python
python 实现将list转成字符串,中间用空格隔开
2019/12/25 Python
django实现日志按日期分割
2020/05/21 Python
5行Python代码实现图像分割的步骤详解
2020/05/25 Python
python两种注释用法的示例
2020/10/09 Python
如何基于Python爬虫爬取美团酒店信息
2020/11/03 Python
详解CSS的border边框属性及其在CSS3中的新特性
2016/05/10 HTML / CSS
谈谈对css属性box-sizing的了解
2017/01/04 HTML / CSS
在HTML5 Canvas中放入图片和保存为图片的方法
2014/05/03 HTML / CSS
英国时尚首饰品牌:Missoma
2020/06/29 全球购物
《雷雨》教学反思
2014/02/20 职场文书
学生会主席竞聘书
2014/03/31 职场文书
医学求职自荐信
2014/06/21 职场文书
大一学生个人总结
2015/02/15 职场文书
CSS Transition通过改变Height实现展开收起元素
2021/08/07 HTML / CSS
最新动漫情报:2022年7月新番定档超过30部, OVERLORD骨王第四季也在其中噢
2022/05/04 日漫