圖靈機器人接口調用限制的解決
昨天我們的文章中說到:使用圖靈機器人作為應答機器人可以滿足要求,但是每天的回復條數在不花錢的情況下只能有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時為粉絲關注,我們判斷收到這樣的消息,就返回需要回復粉絲的內容即可。
當然這樣還會有一些其他的問題,如怎么回復音頻、視頻。這個方法都是類似的,你們可以參考微信公眾號的開發手冊,自己想想該如何解決。