美文网首页python
Python玩微信(2):wxpy的进阶

Python玩微信(2):wxpy的进阶

作者: 陈思煜 | 来源:发表于2017-07-31 12:03 被阅读13262次

    Python玩微信(2):wxpy的进阶

    前记:其实我也不知道这个算不算进阶- -。期初目的是因为我脑海里面有一个设想,通过微信机器人,自动完成对协会招新群的自动添加和群管理,还有自动接受他人报名协会,这些设想在当我发现WXPY这个库后才可以得意实现。一开始想从公众号那边入手的,但自己没有服务器很难弄,如果从其他现成的来弄这些功能的话,1是有限制,2是免费的量很少,3当然是学了就得拿来用一用,试一试。所以就开始写这些了(完整代码见最后面)

    1.自动添加好友

    首先为了自动添加,所以先注册一个好友添加功能的消息,并当好友添加后,自动回复

    addfriend_request = '加好友'  #自动添加好友的条件
    
    
    # 注册好友请求类消息
    @bot.register(msg_types=FRIENDS,enabled=True)
    # 自动接受验证信息中包含 'wxpy' 的好友请求
    def auto_accept_friends(msg):
        # 判断好友请求中的验证文本
        if addfriend_request in msg.text.lower():
            # 接受好友 (msg.card 为该请求的用户对象)
            new_friend = bot.accept_friend(msg.card)
            # 或 new_friend = msg.card.accept()
            # 向新的好友发送消息
            new_friend.send('机器人自动接受了你的请求,你可以任意回复获取功能菜单,若机器人没回复菜单则表明机器人尚未工作,请等待')
    

    2.自动回复好友

    2008904543.jpg

    好友通过非关键字发送可以获取机器人的功能菜单,再通过相应的命令进入其他功能,如果好友没有发送正确的命令,则return 开始菜单

    
    @bot.register(Friend, msg_types=TEXT)
    def exist_friends(msg):
        if menu_1 in msg.text.lower():
            invite(msg.sender)
        else:
            return invite_text 
    
    
    • 拉好友入群
      当好友输入的命令等同于menu_1定义的命令时,机器人自动发送群的邀请给好友,好友点击后可以进入
    admin_puids = frozenset(['XX', 'YY'])   #不可变集合
    admins = list(map(lambda x: bot.friends().search(puid=x), admin_puids))
    
    
    def invite(user):
        groups = sorted(bot.groups(update=True).search(group_name),
                        key=lambda x: x.name)   #sorted用于排序,lambda x:x.name用于群名排序
        if len(groups) > 0:
            for group in groups:
                if len(group.members) == 500:
                    continue    
                if user in group:
                    content = "您已经加入了{} [微笑]".format(group.nick_name)   #经过format格式化的内容传递到{}
                    user.send(content)
                else:
                    group.add_members(user, use_invitation=True)
                return
            else:
                next_topic = group_tmpl.format(re.search(r'\d+', s).group() + 1)  #当前群的名字后面+1
                new_group = bot.create_group(admins, topic=next_topic)
                #以上3句代码的解释为:利用for if else语句进行判断,如果从查找的群名里面找不到对应的群就自动创建一个新群并添加进去
        else:
            print('Invite Failed')
    
    • 表单填写
      先发送填写要求和模板给好友,因为不是表单填写,而且我采用切片提取,所以提取的要求比较高,要求好友的填写要规范
        elif menu_2 in msg.text.lower():
            content_2_1 = "请复制下面的模板回复\nps:部门可以多填,如果是技术部和Hockey就填写 部门:技术部、Hockey\n填写示例:\n姓名:小明\n学号:111111111\n电话:18888888888\n部门:技术部"
            content_2_2 = "报名表\n姓名:\n学号:\n电话:\n部门:"
            msg.sender.send(content_2_1)
            msg.sender.send(content_2_2)
    

    我选择把学号当为主要查询目标(后来想一想,应该是电话号码啊,如果不写入电话号码,怎么联系啊- -)
    先把填写的东东分类提取出来,并和判断是否缴费的一起写入list
    再读取表的内容,查看学号是否填写,如果没有就开始写入,最后再进行是否写入成功的判定
    注意:写入时要改为“a”即追加模式,不然会覆盖表

    1843800684.jpg 深度截图_选择区域_20170730220106.png
    #写表函数
    def table(user, text):
        #提取用户的文本,把有用的写入表里
        msg_text = text
        tables = msg_text.split('\n')
        table_name = tables[1].split(':')[1]
        table_stu_num = tables[2].split(':')[1]
        table_phone_num = tables[3].split(':')[1]
        table_department = tables[4].split(':')[1]
        table_list = [table_name, table_stu_num, table_phone_num, table_department, '等待缴费']
        user.send('请稍等,后台处理中')
        with open(csv_1, 'r') as f:   #检查表里是否有登记的学号
            fr_csv = csv.reader(f)
            for row in fr_csv:
                if table_stu_num in row:
                    user.send('报名失败,该学号已经登记过了')
                    break
            else:
                with open(csv_1, 'a') as f:          #写入表
                    fw_csv = csv.writer(f)
                    fw_csv.writerow(table_list)
                with open(csv_1, 'r') as f:          #查看是否写入成功
                    fr_csv = csv.reader(f)
                    for row in fr_csv:
                        if table_stu_num in row:
                            user.send('报名成功,请回复‘支付宝’或者‘微信’进行支付')
                            break
                    else:
                        user.send('报名失败,请重新报名或者联系管理员')
    
    • 查询
      根据用户输入的学号查看是否缴费成功
      设想是,用户交钱后,管理查看支付宝跟句是否缴费把“等待缴费”改为“缴费成功”
      程序再次打开文件时就能进行查询了
    763504487.jpg
    #查询表函数
    def check(user, text):
        check_text = text.split(':')[1]
        with open(csv_1, 'r') as f:
            fr_csv = csv.reader(f)
            for row in fr_csv:
                if check_text in row:
                    user.send('登记信息如下,如有疑问请联系管理员')
                    user.send('学号:'+row[1]+"\n缴费情况:"+row[-1])
                    break
            else:
                user.send('暂无学号登记记录')   
    
    • 联系管理员(分享名片)
      通过分享名片,让需要联系管理员的好友自己添加管理员
    4838943.jpg
        elif '管理员' in msg.text:
            msg.sender.send('请添加名片联系管理员')
            msg.sender.send_raw_msg(
            # 名片的原始消息类型
            raw_type=42,
            # 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友
            raw_content='<msg username="guanliyuan" nickname="管理员"/>'
            )   
    

    3.处理来自管理员的消息

    这部分比较简单,原本设想的许多功能觉得实用性不高就不添加了(如好友进群@好友提示),管理员这个充当开关的角色也就没什么功能了,只剩下管理员回复备份时能获得表格文件

    1516349912.jpg

    注意:由于注册机制的问题,所以只能优先匹配后注册的(可以查看原文档),所以注册管理员的要放在注册好友回复后面,切管理员无法以好友身份跟机器人互动

    #处理管理员信息
    @bot.register(adminer, msg_types=TEXT)
    def adminer(msg):
        if '备份' in msg.text:
            msg.sender.send_file('test.csv')
        else:
            return "请检查命令是否输入正确"    
    

    4.群聊功能

    采用判断被@时,返回True来获取信息。如果文字里面含有“踢出”且消息来自于管理员时,可以踢掉“踢出”字段后面被@的人。因为只有管理员可以实现这个功能,一般管理员对踢出后面那个人也是自己点头像@的,所以我偷懒省去了被@的不是用户里的人的返回语句了-。-
    如果语句里不含有踢出的话,就是机器人聊天模式了,所有人都可以和机器人聊天,而且WXPY封装挺不错的,几句代码就可以了(见这里),而且他能自动识别用户A上下文,A的问题,B获取不了(描述不太好,见图)

    994467762.jpg 866994332.jpg
    #群聊管理
    @bot.register(my_group, msg_types=TEXT)
    def group(msg):
        if msg.is_at :
            if '踢出' in msg.text:
                if msg.member == group_admin :
                    for member_name in msg.text.split('@')[2:]:
                        print(member_name)
                        re_name = my_group.members.search(member_name)[0].remove()
                        print(re_name)
                        msg.sender.send("已经移出:"+member_name)
                else:
                    return "你不是管理员不能进行踢人操作"
            else:
                xiaoi.do_reply(msg)     
    

    完整代码

    from wxpy import *
    import csv
    
    addfriend_request = '加好友'  #自动添加好友的条件
    admin_request_name = '微信名'    #定义管理员微信名(必须是机器人的好友)  ps:raw_content字段需要自己手动更改微信名,微信号
    admin_request_num = 'weixinhao'   #定义管理员微信号(必须是机器人的好友)
    invite_text = "Helo!回复'功能 + 数字'获取对应功能\n1.我要加群\n2.我要加入协会\n3.我要购买鞋子\n4.了解我们\n5.我需要帮助\n例如:要获取我要加群的功能时回复\n\n功能1"  #任意回复获取的菜单
    group_name = '17中南轮滑协会萌新裙'    #定义要查找群的名字
    menu_1 = '功能1'   #菜单选项1 定义加群的条件
    menu_2 = '功能2'  #菜单选项2
    menu_3 = '功能3'  #菜单选项3
    menu_4 = '功能4'  #菜单选项4  
    menu_5 = '功能5'  #菜单选项5 
    csv_1 = 'test.csv'   #表格1
    
    
    bot = Bot(cache_path = True)
    bot.enable_puid()  #启用聊天对象的puis属性
    xiaoi = XiaoI('PQunMu3c66bM', 'FrQl1oi1YzpDSULeAIit')   #小i机器人接口
    adminer = bot.friends(update=True).search(admin_request_name)[0]
    my_group = bot.groups(update=True).search(group_name)[0]
    group_admin = my_group.members.search(admin_request_name)[0]
    
    
    admin_puids = frozenset(['XX', 'YY'])   #不可变集合
    admins = list(map(lambda x: bot.friends().search(puid=x), admin_puids))
    
    def invite(user):
        groups = sorted(bot.groups(update=True).search(group_name),
                        key=lambda x: x.name)   #sorted用于排序,lambda x:x.name用于群名排序
        if len(groups) > 0:
            for group in groups:
                if len(group.members) == 500:
                    continue    
                if user in group:
                    content = "您已经加入了{} [微笑]".format(group.nick_name)   #经过format格式化的内容传递到{}
                    user.send(content)
                else:
                    group.add_members(user, use_invitation=True)
                return
            else:
                next_topic = group_tmpl.format(re.search(r'\d+', s).group() + 1)  #当前群的名字后面+1
                new_group = bot.create_group(admins, topic=next_topic)
                #以上3句代码的解释为:利用for if else语句进行判断,如果从查找的群名里面找不到对应的群就自动创建一个新群并添加进去
        else:
            print('Invite Failed')
    
    #写表函数
    def table(user, text):
        #提取用户的文本,把有用的写入表里
        msg_text = text
        tables = msg_text.split('\n')
        table_name = tables[1].split(':')[1]
        table_stu_num = tables[2].split(':')[1]
        table_phone_num = tables[3].split(':')[1]
        table_department = tables[4].split(':')[1]
        table_list = [table_name, table_stu_num, table_phone_num, table_department, '等待缴费']
        user.send('请稍等,后台处理中')
        with open(csv_1, 'r') as f:   #检查表里是否有登记的学号
            fr_csv = csv.reader(f)
            for row in fr_csv:
                if table_stu_num in row:
                    user.send('报名失败,该学号已经登记过了')
                    break
            else:
                with open(csv_1, 'a') as f:          #写入表
                    fw_csv = csv.writer(f)
                    fw_csv.writerow(table_list)
                with open(csv_1, 'r') as f:          #查看是否写入成功
                    fr_csv = csv.reader(f)
                    for row in fr_csv:
                        if table_stu_num in row:
                            user.send('报名成功,请回复‘支付宝’或者‘微信’进行支付')
                            break
                    else:
                        user.send('报名失败,请重新报名或者联系管理员')
    
    #查询表函数
    def check(user, text):
        check_text = text.split(':')[1]
        with open(csv_1, 'r') as f:
            fr_csv = csv.reader(f)
            for row in fr_csv:
                if check_text in row:
                    user.send('登记信息如下,如有疑问请联系管理员')
                    user.send('学号:'+row[1]+"\n缴费情况:"+row[-1])
                    break
            else:
                user.send('暂无学号登记记录')   
    
    # 注册好友请求类消息
    @bot.register(msg_types=FRIENDS,enabled=True)
    # 自动接受验证信息中包含 'wxpy' 的好友请求
    def auto_accept_friends(msg):
        # 判断好友请求中的验证文本
        if addfriend_request in msg.text.lower():
            # 接受好友 (msg.card 为该请求的用户对象)
            new_friend = bot.accept_friend(msg.card)
            # 或 new_friend = msg.card.accept()
            # 向新的好友发送消息
            new_friend.send('机器人自动接受了你的请求,你可以任意回复获取功能菜单,若机器人没回复菜单则表明机器人尚未工作,请等待')
    
    #注册自动回复好友消息
    @bot.register(Friend, msg_types=TEXT)
    def exist_friends(msg):
        if menu_1 in msg.text.lower():
            invite(msg.sender)
        elif menu_2 in msg.text.lower():
            content_2_1 = "请复制下面的模板回复\nps:部门可以多填,如果是技术部和Hockey就填写 部门:技术部、Hockey\n填写示例:\n姓名:小明\n学号:111111111\n电话:18888888888\n部门:技术部"
            content_2_2 = "报名表\n姓名:\n学号:\n电话:\n部门:"
            msg.sender.send(content_2_1)
            msg.sender.send(content_2_2)
        elif menu_3 in msg.text.lower():
            return '购买鞋子功能测试中' #跟报名的功能差不多就不写了。。。
        elif menu_4 in msg.text.lower():
            msg.sender.send('关注公众号可以了解更多')
            msg.sender.send_raw_msg(
            # 名片的原始消息类型
            raw_type=42,
            # 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友
            raw_content='<msg username="zdnflunhua" nickname="中大南方RNF"/>'
            )   
        elif menu_5 in msg.text.lower():
            return '我要帮助功能测试中'     #最初设想是返回从公众号获取的素材,结果没有相对应的Api。只能返回图片,语音,或者文本了,不过这个就一行代码的事,就不写了
        elif '报名表' in msg.text.lower():
            table(msg.sender, msg.text)
        elif '支付宝' in msg.text.lower():
            msg.sender.send('请进入支付宝扫描二维码支付,备注姓名,电话\n支付完成后请第二天回复“查询:+学生号“查询情况\n示例:\n查询:111111111')
            msg.sender.send('二维码生成中')
            msg.sender.send_image('zfb.png')
        elif '微信' in msg.text.lower():
            msg.sender.send('请进入微信扫描二维码支付,备注姓名,电话\n支付完成后请第二天回复“查询:+学生号“查询情况\n示例:\n查询:111111111')
            msg.sender.send('二维码生成中')
            msg.sender.send_image('wx.png')
        elif '查询' in msg.text:
            check(msg.sender, msg.text)
        elif '管理员' in msg.text:
            msg.sender.send('请添加名片联系管理员')
            msg.sender.send_raw_msg(
            # 名片的原始消息类型
            raw_type=42,
            # 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友
            raw_content='<msg username="bc9526" nickname="陈思煜"/>'
            )   
        else:
            return invite_text 
    
    #处理管理员信息
    @bot.register(adminer, msg_types=TEXT)
    def adminer(msg):
        if '备份' in msg.text:
            msg.sender.send_file('test.csv')
        else:
            return "请检查命令是否输入正确"    
    
    #群聊管理
    @bot.register(my_group, msg_types=TEXT)
    def group(msg):
        if msg.is_at :
            if '踢出' in msg.text:
                if msg.member == group_admin :
                    for member_name in msg.text.split('@')[2:]:
                        print(member_name)
                        re_name = my_group.members.search(member_name)[0].remove()
                        print(re_name)
                        msg.sender.send("已经移出:"+member_name)
                else:
                    return "你不是管理员不能进行踢人操作"
            else:
                xiaoi.do_reply(msg)     
    bot.join()                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
    
    

    我的博客

    相关文章

      网友评论

      • 9c226e5f5b01:next_topic = group_tmpl.format(re.search(r'\d+', s).group() + 1) #当前群的名字后面+1
        这段是否有误?
      • johnbb2010:Traceback (most recent call last):
        File "C:\wamp64\www\PycharmProjects\untitled\wxchat.py", line 20, in <module>
        print(my_group.members.search('dark丶斌🦄')[0].remove())
        File "C:\Users\24427\venv\lib\site-packages\wxpy\api\chats\member.py", line 37, in remove
        return self.group.remove_members(self)
        File "C:\Users\24427\venv\lib\site-packages\wxpy\utils\misc.py", line 72, in wrapped
        smart_map(check_response_body, ret)
        File "C:\Users\24427\venv\lib\site-packages\wxpy\utils\misc.py", line 207, in smart_map
        return func(i, *args, **kwargs)
        File "C:\Users\24427\venv\lib\site-packages\wxpy\utils\misc.py", line 53, in check_response_body
        raise ResponseError(err_code=err_code, err_msg=err_msg)
        wxpy.exceptions.ResponseError: err_code: 1; err_msg:

        踢人功能不能使用了吗?
      • 480a814ccf9a:from wxpy import *

        bot = Bot()

        test_group = ensure_one(bot.groups().search('test'))
        boss = ensure_one(test_group.search('阴差阳错'))

        @bot.register(test_group, msg_types = TEXT)
        def forword_boss_message(msg):
        if msg.member == boss :
        print('that is right')
        msg.forword(bot.file_helper, prefix = '发言')
        embed()

        这个基本是照着wxpy的文档抄的,为什么运行起来不能如愿呢,它的目的是找到‘阴差阳错’所发的消息然后转发到文件传输助手上,求教,感谢
      • U一点料:你好 可以加一下好友吗, ?
      • 我没有名字你看啥呢:我想麻烦问下,为什么其他功能都可以实现,就踢好友功能无法实现,也不报错,就按着正常聊天一样
        2d35fbd78900:我想问下你的小I接口代码没放上来。按这个源代码应该不支持。
        陈思煜:@我没有名字你看啥呢 太久没用不太清楚了,你看看能否检测消息的类型可以的话就可以实现了。不然可以自己跟小号弄个群 然后发送文字和名片看有什么差异 再判断
        我没有名字你看啥呢:实现了,想请问有没有办法检测群里有人发某一人名片就自动踢出啊
      • 小菜鸟_bbc7:发送好友名片那里有些问题,我发送小号的微信名片,小号点进去显示添加到通信录,并且添加不成功;大号点进去可以添加成功,看不到之前的信息记录,并且大号可以找到之前和小号的聊天记录。感觉很奇妙
      • 丶纳凉:bot.create_group

        这个一直有误,求助

        Traceback (most recent call last):
        File "/Users/husor1/PycharmProjects/untitled/wx.py", line 19, in <module>
        wxq = bot.create_group(admins, topic=None)
        File "/Library/Python/2.7/site-packages/wxpy/api/bot.py", line 395, in create_group
        dict_list = wrap_user_name(self.except_self(ensure_list(users)))
        File "/Library/Python/2.7/site-packages/wxpy/api/bot.py", line 188, in except_self
        return list(filter(lambda x: get_user_name(x) != self.self.user_name, chats_or_dicts))
        File "/Library/Python/2.7/site-packages/wxpy/api/bot.py", line 188, in <lambda>
        return list(filter(lambda x: get_user_name(x) != self.self.user_name, chats_or_dicts))
        File "/Library/Python/2.7/site-packages/wxpy/utils/misc.py", line 261, in get_user_name
        return smart_map(get_one, user_or_users)
        File "/Library/Python/2.7/site-packages/wxpy/utils/misc.py", line 207, in smart_map
        return func(i, *args, **kwargs)
        File "/Library/Python/2.7/site-packages/wxpy/utils/misc.py", line 259, in get_one
        raise TypeError('Unsupported type: {}'.format(type(x)))
        TypeError: Unsupported type: <type 'str'>
        陈思煜:@丶纳凉 你查看一下文档http://wxpy.readthedocs.io/zh/latest/bot.html?highlight=create_group
        admins需要的是不包括自己后的两个用户名,你这样执行后['my', 'xiaojing']是用户my和用户xiaojing,好像是从好友列表里面没这两个用户? 如果你没办法确定用户的puid你可以使用类似bot.friends(update=True).search(admin_request_name)[0]来获取用户。再添加到admins里面
        丶纳凉:admin_puids = frozenset(['my', 'xiaojing']) # 不可变集合
        admins = list(admin_puids)

        wxq = bot.create_group(admins, topic=None)
        wxq.send(u"创建成功")
      • 彭健平6点30:请问怎么延长被微信封的危险
        陈思煜:@彭健平6点30 这个我不清楚哦。。。之前我就运行了10天,没有被封
      • 奔跑的靖Ceo404:求解
        求解
        Getting uuid of QR code.
        Downloading QR code.
        Traceback (most recent call last):
        File "G:/Pyhton/untitled/12306/12306.py", line 3, in <module>
        bot = Bot(cache_path = True)
        File "C:\Python36\lib\site-packages\wxpy\api\bot.py", line 86, in __init__
        loginCallback=login_callback, exitCallback=logout_callback
        File "C:\Python36\lib\site-packages\itchat\components\register.py", line 30, in auto_login
        loginCallback=loginCallback, exitCallback=exitCallback)
        File "C:\Python36\lib\site-packages\itchat\components\login.py", line 44, in login
        picDir=picDir, qrCallback=qrCallback)
        File "C:\Python36\lib\site-packages\itchat\components\login.py", line 117, in get_QR
        utils.print_qr(picDir)
        File "C:\Python36\lib\site-packages\itchat\utils.py", line 85, in print_qr
        os.startfile(fileDir)
        OSError: [WinError 1155] 没有应用程序与此操作的指定文件有关联。: 'QR.png'
        陈思煜:@奔跑的靖Ceo404 我在linux只有一个图库,测不出,谢谢了
        奔跑的靖Ceo404:@陈思煜 已经解决,为题来自,没有设置默认的图片打开方式
        陈思煜:错误描述好像是打不开图片?我没遇到这个问题,你看一看再次使用是否可以?不然改为命令输出模式
      • 2f15267101dc:我扫码之后出现这么一堆是什么。。

        Getting uuid of QR code.
        Downloading QR code.
        Please scan the QR code to log in.
        Please press confirm on your phone.
        Loading the contact, this may take a little while.
        Traceback (most recent call last):
        File "33.py", line 17, in <module>
        bot = Bot(cache_path = True)
        File "I:\SD\lib\site-packages\wxpy\api\bot.py", line 84, in __init__
        loginCallback=login_callback, exitCallback=logout_callback
        File "I:\SD\lib\site-packages\itchat\components\register.py", line 30, in auto
        _login
        loginCallback=loginCallback, exitCallback=exitCallback)
        File "I:\SD\lib\site-packages\itchat\components\login.py", line 66, in login
        self.show_mobile_login()
        File "I:\SD\lib\site-packages\itchat\components\login.py", line 212, in show_m
        obile_login
        self.loginInfo['url'], self.loginInfo['pass_ticket'])
        KeyError: 'pass_ticket'
      • Michael_Scorfie:你好,我自己试了一下,发现手机端登出的时候,网页端也登出了,你是怎么用你小号试验的?两个手机吗?我想将我小号做成机器人,可是大号肯定是需要在手机端常登录的
        陈思煜: @Michael_Scorfie 手机自带双开,你也可以用双开大师

      本文标题:Python玩微信(2):wxpy的进阶

      本文链接:https://www.haomeiwen.com/subject/ednllxtx.html