教你搭建微信公眾號自動答復機器人(下)


​圖靈機器人接口調用限制的解決    

    昨天我們的文章中說到:使用圖靈機器人作為應答機器人可以滿足要求,但是每天的回復條數在不花錢的情況下只能有100條。對於我這樣貧困線人口怎么可能每個月花費99元就為了自動回復呢。於是我就在想還有沒有其它的方式能夠快速做一個請求和應答表呢?

    結合我之前工作上的經驗,那我理解就是直接將請求語句的關鍵詞和需要的回復放在一個Excel表格中,然后直接通過查詢Excel表格這樣也能做到自動回復,說干就干。整個流程如下圖:

    從流程圖上看我們還是在昨天的整體框架上新增后續的容錯處理,一旦檢測到圖靈機器人API請求已用完之后,我們便啟動我們的容錯機制,在我們的Excel表格中去查找我們需要返回的內容,若沒有找到的話,我們就直接返回一個固定語句告訴粉絲朋友,我們現在可能沒有聽懂。

    整體已經說完了,接下來我們就開始實干了。首先我們需要去讀取一個Excel表格,我使用的是xlrd這個庫(一樣啊,安裝方法參考之前的python學習三——庫安裝),由於之前我們已經整理了一個Excel表格的讀寫模塊——ReadAndWriteExcel.py,所以在這里我直接將這個模塊拿過來調用就好了,具體代碼見下:

  1 #   _*_coding=utf-8_*_
  2 import xlwt
  3 import xlrd
  4   5   6 class WriteExcel:
  7     def __init__(self, sheet_name=None):
  8         """初始化寫表格對象
  9  10         :param sheet_name: 寫表格的sheet名,默認為1
 11         """
 12         if sheet_name:
 13             self.sheetname = sheet_name
 14         else:
 15             self.sheetname = "1"
 16         self.workbook = xlwt.Workbook()
 17         self.worksheet = self.workbook.add_sheet(sheetname=self.sheetname)
 18  19     def write_values(self, row, col, values):
 20         """向目標sheet的某個行列寫入值
 21  22         :param row: 目標行
 23         :param col: 目標列
 24         :param values: 想要寫入的值
 25         """
 26         self.worksheet.write(row, col, values)
 27  28     def save_file(self, filename=None):
 29         """保存表格
 30  31         :param filename: 保存的文件名
 32         """
 33         if filename:
 34             self.filename = filename
 35         else:
 36             self.filename = "test.xls"
 37         self.workbook.save(self.filename)
 38  39  40 class OpenExcel:
 41  42     def __init__(self, file_name=None, sheet_id=None):
 43         """初始化讀取Excel表格
 44  45         :param file_name: 需要讀取的表格名
 46         :param sheet_id: 需要讀取的表格sheet
 47         """
 48         if file_name:
 49  50             self.file_name = file_name
 51  52             self.sheet_id = sheet_id
 53  54         else:
 55  56             self.file_name = 'example.xlsx'
 57  58             self.sheet_id = 0
 59  60         self.data = self.get_data()
 61  62     def get_data(self):
 63         """讀取表格數據
 64  65         :return: 返回讀取的表格數據
 66         """
 67         data = xlrd.open_workbook(self.file_name)
 68         tables = data.sheets()[self.sheet_id]
 69         return tables
 70  71     def get_lines(self):
 72         """讀取表格總行數
 73  74         :return: 返回表格總行數
 75         """
 76         tables = self.data
 77         return tables.nrows
 78  79     def get_cols(self):
 80         """讀取表格總行數
 81  82         :return: 返回表格總列數
 83         """
 84         tables = self.data
 85         return tables.ncols
 86  87  88     def get_value(self, row, col):
 89         """讀取表格中具體的行、列對應的值
 90  91         :param row: 目標行
 92         :param col: 目標列
 93         :return: 返回目標行、列的值
 94         """
 95         return self.data.cell_value(row, col)
 96  97  98 if __name__ == '__main__':
 99     openexcel = OpenExcel(file_name="work.xls",sheet_id=0)
100     print (openexcel.get_lines())
101     write_excel = WriteExcel()
102     for j in range(0,openexcel.get_cols()):
103         for i in range(0,openexcel.get_lines()):
104             write_excel.write_values(i,j,openexcel.get_value(i,j))
105     write_excel.write_values(100,100,"我是誰")
106 107 108 109 110     write_excel.save_file()
111

 

接下來我們如下弄一個調用程序來調用ReadAndWriteExcel.py,實現我們根據第一列的關鍵詞返回第二列的回復內容。代碼如下:
import ReadAndWriteExcel
​
def excel_reply(msg):
    """關鍵字回復"""
    keyword_read = ReadAndWriteExcel.OpenExcel(file_name="KeyWord.xlsx",sheet_id=0)
    for i in range(0,keyword_read.get_lines()):
        if msg in keyword_read.get_value(i,0):
            return keyword_read.get_value(i,1)
    if '你叫啥' in msg or '你叫啥名字' in msg:
        return '沃德天·維森莫·拉莫帥·帥德布耀'
    elif '我愛你' in msg:
        return  "我也愛你"
    elif '早安'in msg:
        return "早安啊,朋友"
    else:
        return '我沒有聽懂你在說什么,\n或許我休息一天,\n明天就能智商上線了~'
    pass

 


這里我們不僅僅是通過讀取Excel,也將一些固定的回復放在代碼中進行調試了。接下來我們來看看主程序的代碼。
# -*- coding:utf-8 -*-
from flask import Flask
from flask import request
import hashlib
import tyuling_replay
import time
import re
import ReplayFromExcel
import xml.etree.ElementTree as ET
​
​
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參數
        # my_token = request.args.get('token')
        print(my_signature)
        print(my_timestamp)
        print(my_nonce)
        print(my_echostr)
        # print(my_token)
        token = '123456'     # 一定要跟剛剛填寫的token一致
# 進行字典排序
        data = [token,my_timestamp ,my_nonce ]
        data.sort()
        # 拼接成字符串,進行hash加密時需為字符串
        data = ''.join(data)
        #創建一個hash對象
        s = hashlib.sha1()
        #對創建的hash對象更新需要加密的字符串
        s.update(data.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
                #根據公眾號粉絲的ID生成符合要求的圖靈機器人userid
                if len(fromUser)>31:
                    tuling_userid = str(fromUser[0:30])
                else:
                    tuling_userid = str(fromUser)
                tuling_userid=re.sub(r'[^A-Za-z0-9]+', '', tuling_userid)
                #調用圖靈機器人API返回圖靈機器人返回的結果
                tuling_replay_text = tyuling_replay.get_message(content,tuling_userid)
                #將圖靈機器人返回的內容發送給粉絲
                if '4003' in tuling_replay_text:
                    return reply_text(fromUser, toUser,ReplayFromExcel.excel_reply(content))
                else:
                    return reply_text(fromUser, toUser, tuling_replay_text)
            else:
                return reply_text(fromUser, toUser, "我只懂文字")
​
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)

 


我們在查看圖靈機器人的API文檔發現返回碼為4003時為API接口調用次數已用完,所以我們之前判斷4003是否在API接口的返回信息中,若存在,則圖靈機器人API調用已用完,需要使用Excel備選方案進行答復。

    這樣我們的微信公眾號就再也不會出現服務器異常的報錯了。

圖片和關注的自動回復

    這樣配置了之后,我們還發現了一些問題,如:由於使用了API開發接口,導致公眾號默認的自動化回復無法使用了。一、同樣的關注的自動回復也不能同時使用了;二、上面我們的回復也一直都是針對的文字,對於圖片消息無法進行應答。針對這兩個問題,我們再次對我們的程序進行了優化,新增了關注自動回復和圖片回復原圖的情況。先上代碼:

if msgType == "text":
                content = xml.find('Content').text
                #根據公眾號粉絲的ID生成符合要求的圖靈機器人userid
                if len(fromUser)>31:
                    tuling_userid = str(fromUser[0:30])
                else:
                    tuling_userid = str(fromUser)
                tuling_userid=re.sub(r'[^A-Za-z0-9]+', '', tuling_userid)
                #調用圖靈機器人API返回圖靈機器人返回的結果
                tuling_replay_text = tyuling_replay.get_message(content,tuling_userid)
                #將圖靈機器人返回的內容發送給粉絲
                if '4003' in tuling_replay_text:
                    return reply_text(fromUser, toUser,ReplayFromExcel.excel_reply(content))
                else:
                    return reply_text(fromUser, toUser, tuling_replay_text)
            #關注公眾號的自動答復
            elif msgType == "event":
                Event = xml.find('Event').text
                if Event == "subscribe":
                    subscribe_reply = "菜鳥小白終於等到你~\n" \
                                      "我們可以一起學習打卡,\n" \
                                      "一起努力成長。\n" \
                                      "你煩悶時,我還可以陪你聊天解悶哦~"
                    return reply_text(fromUser, toUser, subscribe_reply)
            elif msgType == "image":
                mediaId = xml.find('MediaId').text
                return reply_image(fromUser, toUser, mediaId)
            else:
                return reply_text(fromUser, toUser, "我只懂文字")
​
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)
def reply_image(to_user, from_user, mediaId):
    """
    以圖片類型的方式回復請求,返回原圖片
    """
    return """
    <xml>
        <ToUserName><![CDATA[{}]]></ToUserName>
        <FromUserName><![CDATA[{}]]></FromUserName>
        <CreateTime>{}</CreateTime>
        <MsgType><![CDATA[image]]></MsgType>
        <Image>
        <MediaId><![CDATA[{}]]></MediaId>
        </Image>
    </xml>
    """.format(to_user, from_user, int(time.time() * 1000), mediaId)
通過對微信公眾號開發文檔的閱讀,我們發現文字類消息和圖片類消息的區分在於msgType,文字類型消息為text,圖片類消息為image。對於圖片類的消息圖片是保存在MediaId字段中,我們只需要將這個在返回給粉絲就好了,就是原圖返給粉絲。

    我們也發現新增粉絲關注時,我們收到的是一個msgType是event,當event中的包含的內容是subscribe時為粉絲關注,我們判斷收到這樣的消息,就返回需要回復粉絲的內容即可。

    當然這樣還會有一些其他的問題,如怎么回復音頻、視頻。這個方法都是類似的,你們可以參考微信公眾號的開發手冊,自己想想該如何解決。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM