跳到正文

做一个免费的微信公众号的自动回复机器人

每天上百条私信,我是如何自动发送校招内推进度的....

Posted by lili on October 2, 2022 · 读取中...

    每天上百条私信,我是如何自动发送校招内推进度的….

    项目背景

    最近帮很多同学进行内推,作为一个有责任心的人,必须要全程帮大家查询内推的投递进度。

    毕竟之前把牛都吹出去了…

    image-20221002191534203

    因此目前的查询流程是

    graph TD
    张三在公众号发送名字-->我每天下班后去后台收集名字-->我去内推的表格中查询张三的进度-->查询后在微信后台回复张三进度
    

    这种淳朴(弱智)的查询方式存在有很多问题。

    • 投递的同学无法及时获得反馈。经常有人连续私信好几条没有回复,误以为是不是私信的格式不对…
    • 私信积攒过多,我也容易眼花,依靠人工很容易出差错。
    • 即使每天统一回复一次,几十甚至上百条的私信也耽误了我大量的休息时间。

    毕竟身为一个程序员,那么我能不能通过自动回复的方式,帮助我自动查询投递进度并发送给你呢?

    需求分析

    • 粉丝能够即时自动的查询航旅校招内推的进度。
    • 成本足够低,最好免费。(毕竟内推费一分钱没到手,总不能让我还往里搭钱吧!)

    先画一个业务的流程图

    graph TD
    粉丝微信后台发送消息-->公众号转发粉丝消息-->是否内推{判断是否属于内推}--yes-->查找excel的内推进度-->组装msg话术并返回-->微信公众号转发回复消息-->粉丝微信收到回复内容
    
    是否内推{判断是否属于内推}--no-->返回查无此人-->微信公众号转发回复消息
    

    是不是看起来还挺简单,既然明确了需求,说干就干!那么我们如何进行技术实现呢?

    技术实现

    将业务流程拆解成技术实现,其实主要分三个步骤。

    graph TD
    解析粉丝微信后台发送消息-->建立微信公众号和本地服务器的通信-->通过本地服务器查找张三的进度并返回
    
    

    首先面向百度编程,找到最简单的就是通过图灵机器人来调用api,轻松的实现智能聊天。但最便宜的版本19.9/月….好吧,直接劝退。

    去github和gitee上找找也没有找到开箱可用的工具。

    那就只能启动我尘封的ide,进行自己开发啦!

    1.微信后台私信收到消息

    这个很简单,微信提供了官方的api,直接监听私信收到的消息即可。

    2.建立微信公众号和本地服务器的通信

    2.1、创建本地web服务器

    既然是做程序开发,就要给程序一个家(服务器)。不过咱既然秉持降本提效的原则,绝不可能花钱买云服务器。那么可不可以把我的电脑当成一个服务器来进行本地开发?当然可以!

    我们先创建一个本地服务器。选择一个你熟悉的技术框架启动一个web服务。

    我这里用的是python的flask,当然springboot啥的也都没问题,这里不多介绍,可以直接百度如何创建一个最简单的web服务。

    启动flask之后,又到了经典的hello world环节。

    image-20220930234222194

    但我们此时搭建的本地服务器是内网环境,只能供我们电脑的浏览器或同一个wifi的手机访问,那如何让别人通过外网能访问到本地服务器呢?这就需要做内网穿透,其实也就是反向代理。

    内网穿透的姿势有很多,本着降本提效的原则,自然是选择简单又免费的natapp。

    2.2、内网穿透

    2.2.1、创建隧道

    进入官网 NATAPP官网,先注册一个NATAPP账号,用来创建隧道。

    image-20220930235054440

    接下来进行隧道配置

    本地地址:默认127.0.0.1

    本地端口:和web服务器启动的端口保持一致我这里是5000

    authtoken:保存下来后面用。

    image-20220930235309057

    2.2.2、下载NATAPP客户端

    官网右上角,按照你的系统下载一个客户端。我选择了Mac OS X 64位,下载后解压到任意目录。

    2.2.3、运行NATAPP

    在natapp的同级目录下创建 config.ini文件。

    1
    2
    3
    4
    5
    6
    
    [default]
    authtoken=1659b9dad1633 //这里填你的隧道号 authtoken
    clienttoken=
    log=none                        
    loglevel=ERROR                  
    http_proxy=  
    

    在Linux/MAC下 需要先给执行权限

    1
    
    chmod a+x natapp
    

    然后执行运行

    1
    
    ./natapp
    

    出现如下界面表示启动成功,natapp会随机分配给你一个域名,外网访问这个域名就可以映射到你本机对应的端口。

    image-20221001001318207

    至此,已经完成了内网的穿透,现在点击http的链接即可访问到我们本地的web服务啦!

    2.3、配置微信公众号后台建立通信

    首先咱得有个公众号吧,在公众号后台开启「开发者模式」。

    设置与开发-基本配置-修改服务器配置。

    URL:使用内网穿透的url。

    Token:自己随便写一串数字或者字母。

    EncodingAESKey:直接点随机生成。

    image-20220930224547640

    点击提交,显示提交成功。

    至此,我们通过flask启动了一个web服务器,并通过NATAPP做内网穿透,最后通过配置建立了微信后台和本地服务器的连接。环境调通,终于到了紧张刺激的写代码环节。

    3.通过本地服务器查找内推进度

    代码的总体逻辑很简单,接收微信公众号发过来的姓名信息,我们对姓名信息进行解析处理。查询该姓名是否在本地excel中,如果在给粉丝return校招进度。

    通过查看微信公众号的开发手册,可以了解到信息处理流程。

    image-20221001005036172

    这样就将微信公众号后台和本地web服务器建立链接了。我们再把收到的xml进行解析,提取出Content信息,通过content可以去excel进行查找和给粉丝回复请求。全部代码如下:

    app.py

    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
    
    # -*- coding:utf-8 -*-
    from flask import Flask
    from flask import request
    import time
    import SelectStudent
    import xml.etree.ElementTree as ET
    import hashlib
    app = Flask(__name__)
    @app.route("/")
    def index():
        return "Hello World!"
    @app.route("/wechat", methods=["GET","POST"])
    def weixin():
        if request.method == "GET":     # 判断请求方式是GET请求
            my_signature = request.args.get('signature')     # 获取携带的signature参数
            my_timestamp = request.args.get('timestamp')     # 获取携带的timestamp参数
            my_nonce = request.args.get('nonce')        # 获取携带的nonce参数
            my_echostr = request.args.get('echostr')         # 获取携带的echostr参数
            token = "123456789"  # 一定要跟刚刚微信开发者设置中填写的token一致
            # 进行字典排序
            data = [token, my_timestamp, my_nonce]
            data.sort()
            # 拼接成字符串,进行hash加密时需要为字符串类型
            temp = ''.join(data)
            # 创建一个hash对象
            s = hashlib.sha1()
            # 对创建的hash对象更新需要加密的字符串
            s.update(temp.encode("utf-8"))
            # 加密处理
            mysignature = s.hexdigest()
            print("handle/GET func: mysignature, my_signature: ", mysignature, my_signature)
            # 加密后的字符串可与signature对比,标识该请求来源于微信
            if my_signature == mysignature:
                return my_echostr
            else:
                return ""
        else:
            # 解析xml
            xml = ET.fromstring(request.data)
            toUser = xml.find('ToUserName').text
            fromUser = xml.find('FromUserName').text
            msgType = xml.find("MsgType").text
            createTime = xml.find("CreateTime")
            # 判断类型并回复
            if msgType == "text":
                content = xml.find('Content').text
                print("content=",content)
                return reply_text(fromUser, toUser, SelectStudent.excel_reply(content))
            else:
                return reply_text(fromUser, toUser, "李梨同学目前只能接收文字哦")
            pass
    def reply_text(to_user, from_user, content):
        """
        以文本类型的方式回复请求
        """
        return """
        <xml>
            <ToUserName><![CDATA[{}]]></ToUserName>
            <FromUserName><![CDATA[{}]]></FromUserName>
            <CreateTime>{}</CreateTime>
            <MsgType><![CDATA[text]]></MsgType>
            <Content><![CDATA[{}]]></Content>
        </xml>
        """.format(to_user, from_user, int(time.time() * 1000), content)
    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=80)
    

    还要写一段查找excel的逻辑,主逻辑非常简单,就不画流程图了。

    • 判断「张三」是否在表格中。
    • 判断「张三」的简历状态。
    • 根据简历状态,拼接文案给粉丝回复。

    SelectStudent.py

    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
    
    import pandas as pd
    def excel_reply(name):
        """关键字回复"""
        df = pd.read_excel('static/candidates2023.xlsx')
        df = df.applymap(lambda x: str(x).strip())#去除表格中的空格
        df_data = df[['候选人姓名', '简历筛选状态']]
        # 判断名字是否在内推的名单中
        if name in df["候选人姓名"].values:
            print("查找的候选人存在")
            # 通过名字查询候选人信息
            candidates = df[df_data["候选人姓名"] == name]
            if candidates['简历筛选状态'].values == "未通过":
                msg = name + "您好,您当前在航旅纵横校招内推的进度为未通过简历筛选,后续依然有招聘机会,期待您的继续关注!"
                return msg
            if candidates['简历筛选状态'].values == "通过":
                msg = name + "您好,您当前在航旅纵横校招内推的进度为通过简历筛选,请等待后续的流程通知!"
                return msg
            if candidates['简历筛选状态'].values == "已发送,待筛选":
                msg = name + "您好,您当前在航旅纵横校招内推的进度为正在业务部门进行筛选,请耐心等待!"
                return msg
            else:
                msg = "您查找的候选人" + name + "不存在,请确认" + name + "是否内推成功。\nPS:李梨同学目前只支持通过姓名查询哦!"
                return msg
        else:
            msg = "您查找的候选人"+name+"不存在,请确认"+name+"是否内推成功。\nPS:李梨同学目前只支持通过姓名查询哦!"
            return msg
    

    我们进入微信对话框进行测试。

    IMG_5118

    大功告成!开心撒花!

    TODO

    • 当前服务部署在本地服务器,当电脑断网关机会导致服务不可用。有空研究下微信云托管来保障服务的稳定性。
    • 接收到长字符串无法处理,系统异常报错。需要增加系统的健壮性。
    • 同名候选人无法处理,直接抛异常。需要做去重处理或增加联合查询。

    20230206补充

    由于flask部署在本地,在本地电脑锁屏断网等情况会导致公众号服务不可用,说白了就还是不稳定,于是准备将这一套迁移到服务器中。

    1. 首先将flask部署到了服务器中,这个网上教程很多做赘述。我用的宝塔部署

    2. 然后在服务器下载个natapp客户端,后台启动。

      ./natapp -authtoken=XXX -log=stdout -loglevel=ERROR

    3. 我的隧道-配置。将127.0.0.1本机ip改为服务器的ip地址。

    4. 配置服务器防火墙,将5000端口开放。

    部署完毕,纵享丝滑!