写在开头:这个功能是小白在学Python中做的小玩意儿。慎用,万一你朋友不小心说了句你不爱听的话,撤回了你没看见,大家还是好朋友;万一你看到了,那友情就打折扣了,这可不好。您也别做啥不合法的事,小白还得准备考研二战~
上篇文章[ 初学python–微信防撤回功能改进(一个用处不大的功能)]中,使用Python的itchat库实现了好友聊天消息防撤回:实现原理,备份两分钟之内的消息,通过撤回通知的信息找到被撤回消息的ID,然后提取发送到文件助手,并保存相关的附件,只能保存在PC,手机没法直接查看;对储存的超时消息进行清理。只有简单的exe,没有界面,也没有Mac和Linux版(穷屌用不上Mac(⋟﹏⋞),怎么开发)。
各位跟我一样的小白,看完这两篇文章,我觉得你应该学会以下内容(不管是看书,上网查资料):字符串及其相关常用函数;元组、列表、字典等数据结构及其常用相关函数的使用;正则表达式及其re库的相关函数;time库的常用函数;文件/文件夹的增删改查(os 和 shutil);itchat库的使用。一定要把基础打牢,不要像我一样求快。最后,欢迎学完这些知识后来重构我的代码或者自己写出来,大家一起学习。
这次的版本中添加了:
1.群聊消息的撤回备份
2.保存的附件并不是零散的堆放在程序文件附近,统一存放在cache中,撤回的消息的附件放在revocation中。
3.实现了发送指令到文件助手可以进行查看删除文件。暂不支持中文名称的文件,还在找原因。
4.支持gif动图,但是不支持微信表情包中表情的撤回及备份
效果图:
撤回消息以及查看:
PC端Cache和Revocation文件夹
各种形式的撤回消息,主要是针对可下载的附件:
(注:看图最后,不支持查看中文文件名的文件,但是中文文件已经保存)
已打包生成exe:http://pan.baidu.com/s/1ckZi14 密码:ksu0
最新版本:修复群聊非好友bug,多谢@嘻笑怒骂提出bug并帮忙改进
链接:http://pan.baidu.com/s/1eRAtqTk 密码:4iy1
最新版本3.0 :群聊添加群聊昵称 链接:http://pan.baidu.com/s/1jHVjOhC 密码:6xc3
双击运行,扫码登陆,即可挂在电脑后台,退出的话从手机点击退出网页版微信
有知友说要弹窗,这样好点儿。有程序界面的版本还得等几天,小白正在努力学习GUI。
微信公众号自动签到功能和查询哪位好友删除自己功能还在实现中,如果可以的话我会第一时间在专栏发布。
刚学Python一个多月,代码和思路远远不够pythonic,请各路大神批评指正,不胜感激(´▽`ʃƪ)
下面是主要代码,大部分跟上篇文章中的代码相似。这个文件功能主要执行发送给文件助手的命令:
查看文件[文件名] e.g. 查看文件[170304-220138.gif]
删除文件[文件名] e.g. 删除文件[170304-220138.gif]
撤回附件列表
有问题请及时通过评论,私信反馈给我,帮我进步,谢谢~
喜欢的话点个赞再走呗~
用着还可以的话赞赏一个更好(●’◡’●)ノ❤
最后是代码~
#WechatForRevocation.py
# -*-encoding:utf-8-*- import os import re import shutil import time import itchat from itchat.content import * import Execution # {msg_id:(msg_from,msg_to,msg_time,msg_time_touser,msg_type,msg_content,msg_url)} msg_store = {} # ClearTimeOutMsg用于清理消息字典,把超时消息清理掉 # 为减少资源占用,此函数只在有新消息动态时调用 def ClearTimeOutMsg(): if msg_store.__len__() > 0: for msgid in list(msg_store): # 由于字典在遍历过程中不能删除元素,故使用此方法 #print("TimeOut:", time.time() - msg_store.get(msgid, None)["msg_time"]) if time.time() - msg_store.get(msgid, None)["msg_time"] > 130.0: # 超时两分钟 item = msg_store.pop(msgid) # 可下载类消息,并删除相关文件 if item['msg_type'] == "Picture" / or item['msg_type'] == "Recording" / or item['msg_type'] == "Video" / or item['msg_type'] == "Attachment": print("要删除的文件:", item['msg_content']) os.remove(".//Cache//" + item['msg_content']) # 将接收到的消息存放在字典中,当接收到新消息时对字典中超时的消息进行清理 # 没有注册note(通知类)消息,通知类消息一般为:红包 转账 消息撤回提醒等,不具有撤回功能 @itchat.msg_register([TEXT, PICTURE, MAP, CARD, SHARING, RECORDING, ATTACHMENT, VIDEO, FRIENDS], isFriendChat=True, isGroupChat=True) def Revocation(msg): # 处理指令 itchat.get_friends(update=True) print("TEst",msg) if msg['ToUserName'] == "filehelper" and msg['Type'] == "Text": result = Execution.Execution(msg) if result[0] == 0: itchat.send(result[1] + r"文件:" + result[2] + r" 失败", toUserName="filehelper") elif result[0] == 1: itchat.send(r"删除文件:" + result[2] + r" 成功", toUserName="filehelper") else: pass return mytime = time.localtime() # 这儿获取的是本地时间 # 获取用于展示给用户看的时间 2017/03/03 13:23:53 msg_time_touser = mytime.tm_year.__str__() / + "/" + mytime.tm_mon.__str__() / + "/" + mytime.tm_mday.__str__() / + " " + mytime.tm_hour.__str__() / + ":" + mytime.tm_min.__str__() / + ":" + mytime.tm_sec.__str__() msg_id = msg['MsgId'] # 消息ID msg_time = msg['CreateTime'] # 消息时间 if itchat.search_friends(userName=msg['FromUserName']): if itchat.search_friends(userName=msg['FromUserName'])['RemarkName']: msg_from = itchat.search_friends(userName=msg['FromUserName'])['RemarkName'] # 消息发送人备注 elif itchat.search_friends(userName=msg['FromUserName'])['NickName']: # 消息发送人昵称 msg_from = itchat.search_friends(userName=msg['FromUserName'])['NickName'] # 消息发送人昵称 else: msg_from = r"读取发送消息好友失败" else: msg_from = msg['ActualNickName'] msg_type = msg['Type'] # 消息类型 msg_content = None # 根据消息类型不同,消息内容不同 msg_url = None # 分享类消息有url # 图片 语音 附件 视频,可下载消息将内容下载暂存到当前目录 if msg['Type'] == 'Text': msg_content = msg['Text'] elif msg['Type'] == 'Picture': msg_content = msg['FileName'] msg['Text'](msg['FileName']) shutil.move(msg_content, r".//Cache//") elif msg['Type'] == 'Card': msg_content = msg['RecommendInfo']['NickName'] + r" 的名片" elif msg['Type'] == 'Map': x, y, location = re.search("<location x=/"(.*?)/" y=/"(.*?)/".*label=/"(.*?)/".*", msg['OriContent']).group(1, 2, 3) if location is None: msg_content = r"纬度->" + x.__str__() + " 经度->" + y.__str__() else: msg_content = r"" + location elif msg['Type'] == 'Sharing': msg_content = msg['Text'] msg_url = msg['Url'] elif msg['Type'] == 'Recording': msg_content = msg['FileName'] msg['Text'](msg['FileName']) shutil.move(msg_content, r".//Cache//") elif msg['Type'] == 'Attachment': msg_content = msg['FileName'] msg['Text'](msg['FileName']) shutil.move(msg_content, r".//Cache//") elif msg['Type'] == 'Video': msg_content = msg['FileName'] msg['Text'](msg['FileName']) shutil.move(msg_content, r".//Cache//") elif msg['Type'] == 'Friends': msg_content = msg['Text'] # print(r"消息提取", # {"msg_from": msg_from, "msg_time": msg_time, "msg_time_touser": msg_time_touser, "msg_type": msg_type, # "msg_content": msg_content, "msg_url": msg_url}) print("消息提取", msg) # 更新字典 # {msg_id:(msg_from,msg_time,msg_time_touser,msg_type,msg_content,msg_url)} msg_store.update( {msg_id: {"msg_from": msg_from, "msg_time": msg_time, "msg_time_touser": msg_time_touser, "msg_type": msg_type, "msg_content": msg_content, "msg_url": msg_url}}) # 清理字典 ClearTimeOutMsg() @itchat.msg_register([NOTE], isFriendChat=True, isGroupChat=True) def SaveMsg(msg): # print(msg) # 创建可下载消息内容的存放文件夹,并将暂存在当前目录的文件移动到该文件中 if not os.path.exists(".//Revocation//"): os.mkdir(".//Revocation//") itchat.search_chatrooms() if re.search(r"/!/[CDATA/[.*撤回了一条消息/]/]", msg['Content']) != None: print("撤回Msg", msg) if re.search("/<msgid/>(.*?)/<//msgid/>", msg['Content']) != None: old_msg_id = re.search("/<msgid/>(.*?)/<//msgid/>", msg['Content']).group(1) elif re.search("/;msgid/>/;(.*?)/<", msg['Content']) != None: old_msg_id = re.search("/;msgid/>/;(.*?)/<", msg['Content']).group(1) old_msg = msg_store.get(old_msg_id, {}) print(r"撤回的消息", old_msg_id, old_msg) if old_msg: msg_send = r"您的好友:" / + old_msg.get('msg_from', None) / + r" 在 [" + old_msg.get('msg_time_touser', None) / + r"], 撤回了一条 [" + old_msg.get('msg_type', None) + "] 消息, 内容如下:" / + old_msg.get('msg_content', None) if old_msg['msg_type'] == "Sharing": msg_send += r", 链接: " / + old_msg.get('msg_url', None) elif old_msg['msg_type'] == 'Picture' / or old_msg['msg_type'] == 'Recording' / or old_msg['msg_type'] == 'Video' / or old_msg['msg_type'] == 'Attachment': msg_send += r", 存储在当前目录下Revocation文件夹中" shutil.move(r".//Cache//" + old_msg['msg_content'], r".//Revocation//") else: msg_send = r"您的好友可能撤回了一个微信表情包,暂时不支持微信表情包,请谅解。" itchat.send(msg_send, toUserName='filehelper') # 将撤回消息的通知以及细节发送到文件助手 msg_store.pop(old_msg_id) if __name__ == '__main__': ClearTimeOutMsg() if not os.path.exists(".//Cache//"): os.mkdir(".//Cache//") itchat.auto_login(hotReload=True) itchat.run()
#Execution.py
import os import re import time import itchat def Execution(message): command = message['Text'] print("command:", command) if re.search(r"(.*?)文件/[(.*?)/]", command): action, filename = re.search(r"(.*?)文件/[(.*?)/]", command).group(1, 2) return ViewDeleteFile(action, filename) elif re.search(r"^公众号签到$", command): return Signin() elif re.search(r"^查询好友状态$", command): return (3,"","") #return FriendStutas() elif re.match(r"^撤回附件列表$", command): return ReturnAttachmentList() else: itchat.send(r"亲,暂时支持以下指令:" r"【查看/删除文件[文件名] e.g.123345234.mp3】 " r"【撤回附件列表(查看都有哪些保存在电脑中的已撤回附件)】 " r"其他指令暂不支持,请期待最新版本。", toUserName="filehelper") return (3, "指令", "失败") def ViewDeleteFile(action, filename): if action == None or filename == None: itchat.send(r"亲,目前支持两种指令:查看/删除文件[文件名] e.g.查看文件[12345678.jpg]", toUserName="filehelper") return (3, "指令", "文件") if action == r"查看": if re.search(r"png|jpg|bmp|jpeg|gif", filename): msg_type = "Picture" elif re.search(r"avi|rm|map4|wmv", filename): msg_type = "Video" else: msg_type = "fil" itchat.send("@%s@%s" % ( {"Picture": "img", "Video": "vid"}.get(msg_type, 'fil'), r".//Revocation//" + filename), toUserName="filehelper") return (2, action, filename) elif action == r"删除": if os.path.exists(r".//Revocation//" + filename): os.remove(r".//Revocation//" + filename) return (1, action, filename) return (0, action, filename) # 查询把自己删除的好友 # 除了一个个添加好友,还有一个实现方式:全部添加进去,然后获取群聊好友列表然后逐个比对。 def FriendStutas(): friendlist = itchat.get_friends()[0:1] delete_friend_list = [] succeed_friend_list = [] chat_topic = r"球队专属聊天群" itchat.create_chatroom(memberList=friendlist, topic=chat_topic) if itchat.search_chatrooms(name=chat_topic): for new_friend in itchat.get_friends()[1:]: result_friend = itchat.add_member_into_chatroom(itchat.search_chatrooms(name=chat_topic)[0]['UserName'], [new_friend]) if result_friend.get('BaseResponse', None).get('ErrMsg', None): print(r"添加结果 ", result_friend) succeed_friend_list.append(new_friend) else: if new_friend['RemarkName']: delete_friend_list.append(new_friend['RemarkName']) else: delete_friend_list.append(new_friend['NickName']) itchat.delete_member_from_chatroom(itchat.search_chatrooms(name=chat_topic)[0]['UserName'], succeed_friend_list) msg_send = r"以下好友把你删除了,请核实:" for item in delete_friend_list: msg_send.join(item + ", ") itchat.send(msg_send, toUserName="filehelper") else: itchat.send(r"查询失败(包括这次一共有三次机会)", toUserName="filehelper") print('#' * 30) print(r"以下好友删除你了...") print("deleted:", delete_friend_list) print(r"以下好友没有删除你:") print("succeed:", succeed_friend_list) print(itchat.search_chatrooms(name=chat_topic)) return (3, "查询", "状态") # 返回撤回附件所有文件名 def ReturnAttachmentList(): filepath = ".//Revocation//" filelist = os.listdir(filepath) if filelist: msg_send = r"所有储存的附件如下:" for item in filelist: msg_send = msg_send + item + ", " itchat.send(msg_send, toUserName="filehelper") else: itchat.send(r"亲,暂时没有撤回的附件", toUserName="filehelper") return (3, "附件列表", "成功") # 微信公众号签到 def Signin(): itchat.send("亲,暂时不支持公众号签到功能,请谅解。", toUserName="filehelper") return (3, "签到", "状态")
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/55125.html