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

本文总阅读量

在网上发现了wxpy这个库,可以调取一些微信API来玩转微信
由于图截得不太好,看图的请访问这里

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

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

1.自动添加好友

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.自动回复好友

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

1
2
3
4
5
6
7
8

@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定义的命令时,机器人自动发送群的邀请给好友,好友点击后可以进入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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')
  • 表单填写
    先发送填写要求和模板给好友,因为不是表单填写,而且我采用切片提取,所以提取的要求比较高,要求好友的填写要规范
    1
    2
    3
    4
    5
    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”即追加模式,不然会覆盖表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #写表函数
    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('报名失败,请重新报名或者联系管理员')
  • 查询
    根据用户输入的学号查看是否缴费成功
    设想是,用户交钱后,管理查看支付宝跟句是否缴费把“等待缴费”改为“缴费成功”
    程序再次打开文件时就能进行查询了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #查询表函数
    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('暂无学号登记记录')
  • 联系管理员(分享名片)
    通过分享名片,让需要联系管理员的好友自己添加管理员
    1
    2
    3
    4
    5
    6
    7
    8
    elif '管理员' in msg.text:
    msg.sender.send('请添加名片联系管理员')
    msg.sender.send_raw_msg(
    # 名片的原始消息类型
    raw_type=42,
    # 注意 `username` 在这里应为微信 ID,且被发送的名片必须为自己的好友
    raw_content='<msg username="guanliyuan" nickname="管理员"/>'
    )

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

    这部分比较简单,原本设想的许多功能觉得实用性不高就不添加了(如好友进群@好友提示),管理员这个充当开关的角色也就没什么功能了,只剩下管理员回复备份时能获得表格文件
    注意:由于注册机制的问题,所以只能优先匹配后注册的(可以查看原文档),所以注册管理员的要放在注册好友回复后面,切管理员无法以好友身份跟机器人互动
    1
    2
    3
    4
    5
    6
    7
    #处理管理员信息
    @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获取不了(描述不太好,见图)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #群聊管理
    @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)

    完整代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    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()

查看评论