撤回我也能看到!教你用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的random模块吗?
Dec 12 Python
python导入csv文件出现SyntaxError问题分析
Dec 15 Python
python装饰器-限制函数调用次数的方法(10s调用一次)
Apr 21 Python
更换Django默认的模板引擎为jinja2的实现方法
May 28 Python
python3实现字符串的全排列的方法(无重复字符)
Jul 07 Python
Python OpenCV处理图像之图像像素点操作
Jul 10 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
Feb 27 Python
用python打印1~20的整数实例讲解
Jul 01 Python
python按修改时间顺序排列文件的实例代码
Jul 25 Python
python网络爬虫 CrawlSpider使用详解
Sep 27 Python
基于tensorflow for循环 while循环案例
Jun 30 Python
OpenCV读取与写入图片的实现
Oct 13 Python
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
matplotlib如何设置坐标轴刻度的个数及标签的方法总结
PyQt5结合QtDesigner实现文本框读写操作
Python中seaborn库之countplot的数据可视化使用
You might like
利用php绘制饼状图的实现代码
2013/06/07 PHP
ThinkPHP视图查询详解
2014/06/30 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
2016/01/08 PHP
PHP中抽象类、接口的区别与选择分析
2016/03/29 PHP
phpcms的分类名称和类别名称的调用
2017/01/05 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
2019/08/03 PHP
php获取是星期几的的一些常用姿势
2019/12/15 PHP
表单的一些基本用法与技巧
2006/07/15 Javascript
与jquery serializeArray()一起使用的函数,主要来方便提交表单
2011/01/31 Javascript
jquery showModelDialog的使用方法示例详解
2013/11/19 Javascript
一个JavaScript的求爱小特效
2014/05/09 Javascript
jquery实现倒计时效果
2015/12/14 Javascript
JavaScript reduce和reduceRight详解
2016/10/24 Javascript
vue-cli+webpack记事本项目创建
2017/04/01 Javascript
EasyUI创建人员树的实例代码
2017/09/15 Javascript
vue中的自定义分页插件组件的示例
2018/08/18 Javascript
Vue 3.0 前瞻Vue Function API新特性体验
2019/08/12 Javascript
JS设置自定义快捷键并实现图片上下左右移动
2019/10/17 Javascript
python正则表达式修复网站文章字体不统一的解决方法
2013/02/21 Python
Python中json格式数据的编码与解码方法详解
2016/07/01 Python
基于python实现在excel中读取与生成随机数写入excel中
2018/01/04 Python
在Python 2.7即将停止支持时,我们为你带来了一份python 3.x迁移指南
2018/01/30 Python
python射线法判断一个点在图形区域内外
2019/06/28 Python
django多文件上传,form提交,多对多外键保存的实例
2019/08/06 Python
最新Python idle下载、安装与使用教程图文详解
2020/11/28 Python
plt.figure()参数使用详解及运行演示
2021/01/08 Python
学习党章思想汇报
2014/01/07 职场文书
写自荐信三大法宝
2014/01/24 职场文书
公务员转正鉴定材料
2014/02/11 职场文书
詹天佑教学反思
2014/04/30 职场文书
爱祖国演讲稿
2014/05/04 职场文书
社区活动总结报告
2014/05/05 职场文书
教师党的群众路线教育实践活动剖析材料
2014/10/09 职场文书
幼儿园家长工作总结2015
2015/04/25 职场文书
四群教育工作总结
2015/08/10 职场文书
解析CSS 提取图片主题色功能(小技巧)
2021/05/12 HTML / CSS