撤回我也能看到!教你用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定时器使用示例分享
Feb 16 Python
详解python使用递归、尾递归、循环三种方式实现斐波那契数列
Jan 16 Python
Python生成任意范围任意精度的随机数方法
Apr 09 Python
numpy中实现ndarray数组返回符合特定条件的索引方法
Apr 17 Python
Python基于lxml模块解析html获取页面内所有叶子节点xpath路径功能示例
May 16 Python
Python重新加载模块的实现方法
Oct 16 Python
python列表使用实现名字管理系统
Jan 30 Python
Python如何爬取微信公众号文章和评论(基于 Fiddler 抓包分析)
Jun 28 Python
用python建立两个Y轴的XY曲线图方法
Jul 08 Python
python redis 批量设置过期key过程解析
Nov 26 Python
Python动态声明变量赋值代码实例
Dec 30 Python
python 等差数列末项计算方式
May 03 Python
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
matplotlib如何设置坐标轴刻度的个数及标签的方法总结
PyQt5结合QtDesigner实现文本框读写操作
Python中seaborn库之countplot的数据可视化使用
You might like
DC四月将推出百页特刊漫画 纪念小丑诞生80周年
2020/04/09 欧美动漫
php与paypal整合方法
2010/11/28 PHP
php检查页面是否被百度收录
2015/10/28 PHP
学习php设计模式 php实现单例模式(singleton)
2015/12/07 PHP
CodeIgniter集成smarty的方法详解
2016/05/26 PHP
php微信开发之上传临时素材
2016/06/24 PHP
thinkPHP框架实现图像裁剪、缩放、加水印的方法
2017/03/14 PHP
js 鼠标拖动对象 可让任何div实现拖动效果
2009/11/09 Javascript
js确认删除对话框适用于a标签及submit
2014/07/10 Javascript
javascript框架设计之类工厂
2015/06/23 Javascript
jQuery插件FusionWidgets实现的Cylinder图效果示例【附demo源码】
2017/03/23 jQuery
Vue前后端不同端口的实现方法
2018/09/19 Javascript
vue如何解决循环引用组件报错的问题
2018/09/22 Javascript
2019 年编写现代 JavaScript 代码的5个小技巧(小结)
2019/01/15 Javascript
vue 进阶之实现父子组件间的传值
2019/04/26 Javascript
vue实现吸顶、锚点和滚动高亮按钮效果
2019/10/21 Javascript
vue实现Input输入框模糊查询方法
2021/01/29 Javascript
JavaScript中while循环的基础使用教程
2020/08/11 Javascript
[08:47]DOTA2每周TOP10 精彩击杀集锦vol.6
2014/06/25 DOTA
Python cookbook(数据结构与算法)同时对数据做转换和换算处理操作示例
2018/03/23 Python
python实现将一个数组逆序输出的方法
2018/06/25 Python
详解Python传入参数的几种方法
2019/05/16 Python
Python实现语音识别和语音合成功能
2019/09/20 Python
python 使用while写猜年龄小游戏过程解析
2019/10/07 Python
pandas中ix的使用详细讲解
2020/03/09 Python
Python使用monkey.patch_all()解决协程阻塞问题
2020/04/15 Python
Python 如何实现数据库表结构同步
2020/09/29 Python
日本最新流行服饰网购:Nissen
2016/07/24 全球购物
欧洲最大的化妆品连锁公司:Douglas道格拉斯
2017/05/06 全球购物
FC-Moto瑞典:欧洲最大的摩托车服装和头盔商店之一
2018/11/27 全球购物
自动化工程专业个人应聘自荐信
2013/09/26 职场文书
法制宣传月活动总结
2014/04/29 职场文书
纪检干部现实表现材料
2014/08/21 职场文书
敬老月活动总结
2014/08/28 职场文书
教学督导岗位职责
2015/04/10 职场文书
大学校园餐饮创业计划书
2019/08/07 职场文书