想查看微信好友撤回的消息?Python帮你搞定
-
前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。
作者:~wangweijunPython微信防撤回小程序,
当你用微信和对方聊天时,对方突然撤回了几条消息,你会好奇吗?你会很想知道对方撤回了什么吗? Python实现的微信防撤回小程序,让你轻松获取对方撤回的消息内容
要说微信最让人恶心的发明,消息撤回绝对能上榜。
比如你现在正和女朋友用微信聊着天,或者跟自己喜欢的女孩子聊着天,一个不留神,你没注意到对方发的消息就被她及时撤回了,这时你很好奇,好奇她到底发了什么?于是你打算问问她发了什么,结果她回一句”没什么”。这一回复,让你的好奇心更加强烈了,顿时就感觉消息撤回这一功能就是用来折磨人的。
那么有没有什么办法能够知道你心爱的她(他)到底撤回了什么呢?不要着急,Python帮你搞定。如果你还不会写python小程序,建议你去小编的Python交流.裙 :一久武其而而流一思(数字的谐音)转换下可以找到了,里面有最新Python教程项目,多跟他们交流,你会进步很快!
模块介绍
本篇文章将用Python实现微信的防撤回功能,针对微信操作,Python有一个十分强大的库:itchat。相信没有使用过也有所耳闻吧。官方是这样描述它的:
Project description
itchat is a open souce wechat api project for personal account.
It enables you to access your personal wechat account through command line.
翻译过来就是:itchat是一个针对个人帐户的开放式微信api项目,它使您可以通过命令行访问您的个人微信帐户。
既然是针对微信的开发,我们就离不开这个模块的协助,所以,首先下载该模块:
pip install itchat
也可以在开发工具Pycharm中直接导入该模块,Pycharm会提示你下载。
模块初体验
考虑到应该有些人从来没有使用过该模块,这里对该模块进行一个简单的入门。
1、如何登陆微信
既然要操作微信,那么摆在我们面前的问题就是如何登录微信,登录微信非常简单,直接看代码:
import itchat
itchat.login()
没错,一句代码即可完成登录,运行之后就会弹出一个二维码,扫描之后在手机上授权登录,控制台就会提示是否登录成功。
Login successfully as Y
这样就说明登录成功了。
这里需要注意一个问题,就是你会发现每次运行程序都要扫描二维码登录,这样未免太麻烦,有没有办法只扫描一次,以后就自动登录了呢?这当然是可以的。
import itchat
itchat.auto_login(hotReload=True)
通过函数名也能知道该方法可以实现自动登录,运行程序,扫码登录之后会在项目路径下创建一个itchat.pkl文件,该文件用于存储登录的状态,所以千万不要动它,如果你想换一个微信账号登录,就要先把这个文件删除,因为该文件记录的是上一个微信的状态,删除之后即可登录。
需要注意:这种方式只能保证你在短时间内无需重复登录,时间长了,还是需要重新扫码登录的。
进行到这里,有些人可能会发现自己的微信登录不上的情况,据我所知,有些新注册的微信和长期不使用的微信是无法登录网页版微信的,所以这里也会导致登录不上。如果登录不上,那也是没有办法的,下面的内容也就没有意义了。
2、获取好友列表
登录上微信之后,我们来用一用itchat模块提供的一些api,比如获取好友列表。
import itchat
itchat.auto_login(hotReload=True)
friends = itchat.get_friends() # 好友列表
print(friends)
使用get_friends()函数即可获取到好友列表的所有好友信息,包括昵称、备注名、地址、个性签名、性别等等。
这里我随意地复制了一个好友的个人信息,当然由于隐私问题,这里的部分信息我用”*”号代替了,我们重点是分析一下这些信息的内容。比如最开始的UserName,这是用户的唯一标识,相当于身份证号码,你的每个好友都会有这样一个标识,每个好友之间肯定都是不一样的;然后是NickName,这是好友的昵称;HeadImgUrl是好友的头像地址;RemarkName是你对好友的备注名;Province是省份等等,这里就不一一介绍了,感兴趣的话可以自己去了解一下。
3、如何发送消息给好友
如何发送一条消息给指定的好友呢?也非常简单:
import itchat
itchat.auto_login(hotReload=True)
itchat.send(\'Hello World\', toUserName=\'@f9e42aafa1175b38b60a0be4d651a34c77f2528d9b7784e7aaf415090eca8fa6\')
此时的UseName就派上用场了,也就是好友的唯一标识,这样,我们就给该标识对应的好友发送了一条消息,所以,我们可以这样改进程序:
import itchat
itchat.auto_login(hotReload=True)
friends = itchat.get_friends()
nickName = \'诚信通授权渠道商-老曾\'
for i in friends:
if \'诚信通授权渠道商-老曾\' == i[\'NickName\']:
itchat.send(\'Hello World\', toUserName=i[\'UserName\'])
break
这样,就可以指定发送给任意好友,通过好友的昵称在好友列表中进行检索,找到的话,就获取该好友的UserName,然后发送消息,也可以通过对好友的备注名(RemarkName)查找,大家可以自己尝试。
4、装饰器
关于itchat模块还有很多功能,这里就不作过多讲解了,我们只讲关于这次程序的知识点,这里是最后一个内容,装饰器。
关于装饰器,一时半会还讲不清楚,这里只是简单介绍一下,装饰器的作用就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。
例如现在有一个函数fun(),你并不知晓函数的实现原理,你肯定也不能去修改这个函数的代码,而你需要给该函数添加一个输出开始运行时间和结束运行时间的功能,该如何实现呢?这个时候就可以使用装饰器。
import time
def show_time(fun):
def inner():
print(time.time())
fun()
print(time.time())
return inner
@show_time
def fun():
pass
fun()
该如何理解这段程序呢?首先@show_time即是使用一个装饰器show_time,此时会将装饰的函数,也就是fun()作为参数传递给装饰器show_time(),我们知道函数作为返回值的话,执行的其实是该函数,所以程序会执行内部函数inner(),此时输出开始运行时间,然后调用fun()函数(原有的功能不能丢),最后输出结束运行时间。这样就通过装饰器实现了一个函数的功能扩展,这也是典型的面向切面编程思想。
如何获取好友发送的消息
准备工作做完了,接下来就进入正题了,对于上面的知识点,大家一定要掌握,如果不懂的话,接下来的代码你可能会很懵。
首先,我们看看该如何获取到好友发送的消息。
import itchat
itchat.auto_login(hotReload=True)
@itchat.msg_register(itchat.content.TEXT)
def resever_info(msg):
print(msg)
itchat.run() #保持
itchat模块提供了@itchat.msg_register装饰器来监听消息,比如这里我们自定义了一个resever_info()函数,并用装饰器对消息进行监听,装饰器中传入了itchat.content.TEXT类型,这样监听的就是文本消息,监听到输入之后,装饰器就会将文本消息传入resever_info()的参数中。所以,msg就是监听到的消息内容。
对于@itchat.msg_register装饰器,它不仅可以监听文本,还可以监听语音、图片、地图、名片、视频等等,为了方便,这里我们导入itchat模块下的content模块中的全部内容,因为这些消息类型都是在该模块下声明的。
TEXT = \'Text\'
MAP = \'Map\'
CARD = \'Card\'
NOTE = \'Note\'
SHARING = \'Sharing\'
PICTURE = \'Picture\'
RECORDING = VOICE = \'Recording\'
ATTACHMENT = \'Attachment\'
VIDEO = \'Video\'
FRIENDS = \'Friends\'
SYSTEM = \'System\'
INCOME_MSG = [TEXT, MAP, CARD, NOTE, SHARING, PICTURE,
RECORDING, VOICE, ATTACHMENT, VIDEO, FRIENDS, SYSTEM]
还有要注意的地方,最后记得调用itchat的run()函数,保持程序运行,否则程序就直接结束了。
接下来我们就可以测试一下了,我让我的好友发了一条消息给我,控制台就输出了如下内容:
内容很多,我们只挑重要的看。例如FromUserName,这是发送者的标识;ToUserName,这是接收者的标识;Content,这当然就是文本内容了;CreateTime,这是发送时间;注意最后的两个值:Type,这是消息类型,这里是文本类型Text,然后Text也是文本内容,所以如果想取出好友发送的消息内容的话,用Content和Text都可以。分析过后,取出内容就很简单了:
import itchat
import time
from itchat.content import * # 导入itchat下的content模块
itchat.auto_login(hotReload=True)
@itchat.msg_register(TEXT)
def resever_info(msg):
info = msg[\'Text\'] # 取出文本消息
info_type = msg[\'Type\'] # 取出消息类型
fromUser = itchat.search_friends(userName=msg[\'FromUserName\'])[\'NickName\']
ticks = msg[\'CreateTime\'] # 获取信息发送的时间
time_local = time.localtime(ticks)
dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local) # 格式化日期
print("发送人:" + fromUser + \'\n消息类型:\' + info_type + \'\n发送时间:\' + dt + \'\n消息内容:\' + info)
itchat.run(
这里用到了time模块,用于格式化日期。
为了测试方便,我就自己发了一条消息给别人,自己发的消息也是会被监听的,看运行结果:
发送人:Y
消息类型:Text
发送时间:2019-11-28 16:19:13
消息内容:土鳖
再来试试语音和图片能获取到吗?我们回到刚才的代码:
import itchat
from itchat.content import * # 导入itchat下的content模块
itchat.auto_login(hotReload=True)
@itchat.msg_register(TEXT)
def resever_info(msg):
print(msg)
itchat.run()
运行之后,发送语音和图片试试,不管怎么发,控制台就是没反应,这是当然的了,我们还没对语音和图片进行监听呢,修改代码:
import itchat
from itchat.content import * # 导入itchat下的content模块
itchat.auto_login(hotReload=True)
@itchat.msg_register([TEXT, PICTURE, RECORDING]) #添加了对图片和语音的监听
def resever_info(msg):
print(msg)
itchat.run()
再运行试试,先发送一张图片,再发送一段语音,控制台输出了两段内容,由于篇幅过长,就不贴出来了,无非还是那些信息,发送者,接收者,日期,消息内容等等,这里只需注意图片和语音的内容:
\'Type\': \'Picture\', \'Text\': <function get_download_fn.<locals>.download_fn at 0x0000000003574158>
\'Type\': \'Recording\', \'Text\': <function get_download_fn.<locals>.download_fn at 0x0000000002CFED08>
这是一段地址,通过它我们就能够将图片和语音保存起来。
如何保存好友发送的图片和语音
下面我们对好友发送的图片和语音进行保存。
import itchat
import os
from itchat.content import * # 导入itchat下的content模块
itchat.auto_login(hotReload=True)
temp = \'C:/Users/Administrator/Desktop/CrawlerDemo\' + \'/\' + \'撤回的消息\'
# 如果不存在该文件夹,就创建
if not os.path.exists(temp):
os.mkdir(temp)
@itchat.msg_register([TEXT, PICTURE, RECORDING])
def resever_info(msg):
info = msg[\'Text\'] # 取出文本消息
info_type = msg[\'Type\'] # 取出消息类型
name = msg[\'FileName\'] # 取出语音(图片)文件名
if info_type == \'Recording\':
# 保存语音
info(temp + \'/\' + name)
elif info_type == \'Picture\':
# 保存图片
info(temp + \'/\' + name)
itchat.run()
运行起来,然后发送一张图片和一条语音,就会在指定目录下生成两个文件:
如何监听好友撤回了消息
到这里,我们其实已经完成了消息监听,只需要稍加修改即可,但是这个程序是有缺陷的,因为不是所有消息我们都需要去保存的,好友正常发送过来的消息我们直接就能看到,保存下来不是多此一举吗?我们的目的是想知道好友撤回了什么内容,这就涉及到如何监听好友是否撤回了消息这一问题了。其实也非常简单,Content模块为我们提供了NOTE类型,该类型指的是系统消息。
所以我们可以自定义一个函数用来监听系统消息:
import itchat
from itchat.content import * # 导入itchat下的content模块
itchat.auto_login(hotReload=True)
@itchat.msg_register(NOTE)
def note_info(msg): # 监听系统消息
print(msg)
itchat.run()
运行程序,我们撤回一条消息测试一下,输出结果如下:
......
\'DisplayName\': \'\', \'ChatRoomId\': 0, \'KeyWord\': \'\', \'EncryChatRoomId\': \'\', \'IsOwner\': 0}>, \'Type\': \'Note\', \'Text\': \'你撤回了一条消息\'}
......
这里截取了部分内容,会发现,撤回消息的文本内容为”你撤回了一条消息”,所以要想知道好友是否撤回了消息就非常简单了,判断msg[\'Text\'] == \'你撤回了一条消息\'
即可。
实现微信防撤回程序
关于程序每个步骤的代码到这里就分析完了,接下来是对所有代码的汇总,也是整个程序的完整代码:
import itchat
from itchat.content import *
import os
import time
import xml.dom.minidom # 解析xml模块
# 这是保存撤回消息的文件目录(如:图片、语音等),这里已经写死了,大家可以自行修改
temp = \'C:/Users/Administrator/Desktop/CrawlerDemo\' + \'/\' + \'撤回的消息\'
if not os.path.exists(temp):
os.mkdir(temp)
itchat.auto_login(True) # 自动登录
dict = {} # 定义一个字典
# 这是一个装饰器,给下面的函数添加新功能
# 能够捕获好友发送的消息,并传递给函数参数msg
@itchat.msg_register([TEXT, PICTURE, FRIENDS, CARD, MAP, SHARING, RECORDING, ATTACHMENT, VIDEO]) # 文本,语音,图片
def resever_info(msg):
global dict # 声明全局变量
info = msg[\'Text\'] # 取出消息内容
msgId = msg[\'MsgId\'] # 取出消息标识
info_type = msg[\'Type\'] # 取出消息类型
name = msg[\'FileName\'] # 取出消息文件名
# 取出消息发送者标识并从好友列表中检索
fromUser = itchat.search_friends(userName=msg[\'FromUserName\'])[\'NickName\']
ticks = msg[\'CreateTime\'] # 获取信息发送的时间
time_local = time.localtime(ticks)
dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local) # 格式化日期
# 将消息标识和消息内容添加到字典
# 每一条消息的唯一标识作为键,消息的具体信息作为值,也是一个字典
dict[msgId] = {"info": info, "info_type": info_type, "name": name, "fromUser": fromUser, "dt": dt}
@itchat.msg_register(NOTE) # 监听系统提示
def note_info(msg):
# 监听到好友撤回了一条消息
if \'撤回了一条消息\' in msg[\'Text\']:
# 获取系统消息中的Content结点值
content = msg[\'Content\']
# Content值为xml,解析xml
doc = xml.dom.minidom.parseString(content)
# 取出msgid标签的值
result = doc.getElementsByTagName("msgid")
# 该msgId就是撤回的消息标识,通过它可以在字典中找到撤回的消息信息
msgId = result[0].childNodes[0].nodeValue
# 从字典中取出对应消息标识的消息类型
msg_type = dict[msgId][\'info_type\']
if msg_type == \'Recording\': # 撤回的消息为语音
recording_info = dict[msgId][\'info\'] # 取出消息标识对应的消息内容
info_name = dict[msgId][\'name\'] # 取出消息文件名
fromUser = dict[msgId][\'fromUser\'] # 取出发送者
dt = dict[msgId][\'dt\'] # 取出发送时间
recording_info(temp + \'/\' + info_name) # 保存语音
# 拼接提示消息
send_msg = \'【发送人:】\' + fromUser + \'\n\' + \'发送时间:\' + dt + \'\n\' +