IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    初学Python–微信好友/群消息防撤回,查看相关附件

    铁匠发表于 2017-03-31 07:05:45
    love 0

    写在开头:这个功能是小白在学Python中做的小玩意儿。慎用,万一你朋友不小心说了句你不爱听的话,撤回了你没看见,大家还是好朋友;万一你看到了,那友情就打折扣了,这可不好。您也别做啥不合法的事,小白还得准备考研二战~

    上篇文章[ 初学python--微信防撤回功能改进(一个用处不大的功能)]中,使用Python的itchat库实现了好友聊天消息防撤回:实现原理,备份两分钟之内的消息,通过撤回通知的信息找到被撤回消息的ID,然后提取发送到文件助手,并保存相关的附件,只能保存在PC,手机没法直接查看;对储存的超时消息进行清理。只有简单的exe,没有界面,也没有Mac和Linux版(穷屌用不上Mac(⋟﹏⋞),怎么开发)。

    各位跟我一样的小白,看完这两篇文章,我觉得你应该学会以下内容(不管是看书,上网查资料):字符串及其相关常用函数;元组、列表、字典等数据结构及其常用相关函数的使用;正则表达式及其re库的相关函数;time库的常用函数;文件/文件夹的增删改查(os 和 shutil);itchat库的使用。一定要把基础打牢,不要像我一样求快。最后,欢迎学完这些知识后来重构我的代码或者自己写出来,大家一起学习。

    这次的版本中添加了:

    1.群聊消息的撤回备份

    2.保存的附件并不是零散的堆放在程序文件附近,统一存放在cache中,撤回的消息的附件放在revocation中。

    3.实现了发送指令到文件助手可以进行查看删除文件。暂不支持中文名称的文件,还在找原因。

    4.支持gif动图,但是不支持微信表情包中表情的撤回及备份

    效果图:

    撤回消息以及查看:

    初学Python--微信好友/群消息防撤回,查看相关附件PC端Cache和Revocation文件夹

    初学Python--微信好友/群消息防撤回,查看相关附件初学Python--微信好友/群消息防撤回,查看相关附件各种形式的撤回消息,主要是针对可下载的附件:

    初学Python--微信好友/群消息防撤回,查看相关附件初学Python--微信好友/群消息防撤回,查看相关附件初学Python--微信好友/群消息防撤回,查看相关附件

    (注:看图最后,不支持查看中文文件名的文件,但是中文文件已经保存)

    已打包生成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

    初学Python--微信好友/群消息防撤回,查看相关附件

    双击运行,扫码登陆,即可挂在电脑后台,退出的话从手机点击退出网页版微信

    初学Python--微信好友/群消息防撤回,查看相关附件初学Python--微信好友/群消息防撤回,查看相关附件初学Python--微信好友/群消息防撤回,查看相关附件

    有知友说要弹窗,这样好点儿。有程序界面的版本还得等几天,小白正在努力学习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\&gt\;(.*?)\&lt", msg['Content']) != None:
                old_msg_id = re.search("\;msgid\&gt\;(.*?)\&lt", 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, "签到", "状态")


沪ICP备19023445号-2号
友情链接