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

写在开头:这个功能是小白在学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, "签到", "状态")

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/55125.html

(0)
上一篇 2021年8月7日
下一篇 2021年8月7日

相关推荐

发表回复

登录后才能评论