網站改版|WAP網站制作|域名注冊|虛擬主機|服務器|海微商|海微信|海微通| 24小時服務電話:13807590485
海南網站建設海南網站制作海口網站建設三亞網站建設儋州網站建設五指山網站建設文昌網站建設瓊海網站建設萬寧網站建設東方網站建設定安網站建設 網站首頁網站首頁 網站建設網站建設 微信開發微信開發 網站推廣網站推廣 海南網站建設,海南網站開發制作,海南網頁設計,海南小程序開發,海南微信公眾號開發,海南網絡公司,海南世紀華聯海南世紀華聯 網站超市網站超市 客戶案例客戶案例 網站模板網站模板 關于我們關于我們
微信開發
微信系統開發 微信開發功能 公眾號基礎教程 開發技術資訊 公眾號推廣營銷 客戶案例
聯系我們
QQ服務群:28519571 工作時間:86-0898-31568080 傳真號碼:86-0898-31568085 24小時服務:0138-07590485
 您現在的位置: 首頁 >> 微信開發 >> 開發技術資訊 開發技術資訊
微信機器人:有道翻譯小助手——Django + SAE + 微信公眾帳號自動回復開放接口
世紀華聯 | 2018-01-26 23:32:14 | 閱讀:4429
Sina App Engine

  首先作為一個屌絲開發者要解決服務器的問題。去SAE的官網上用新浪微博的帳號注冊一個帳號,成功后會贈給你500云豆,可供一個開發者試用大概5天。SAE非常優秀,如果以后我們想在上面寫點應用什么的,可以去申請實名認證和開發者認證,那樣每個月都會給你一定數量的云豆,應該能滿足日常需求。由于現在SAE上部署Python還處于公測階段,因此我們要去申請開通可以在上面部署Python程序的權限,現在很好申請的,不一會就會收到已經為你開放了部署Python應用權限的郵件,網上搜到的啥啥還需要排隊都是過去了(不排除當你看到這篇文章時SAE已經可以允許所有開發者部署Python的應用了)。
 

  OK,完成這些后,就可以到SAE的文檔中心讀文檔來照著文檔里面的樣例創建一個應用了。

  有道API

  然后,去有道API申請一個key,申請的時候網站地址隨便填就行。有道API非常簡單,直接以GET的形式把要翻譯的文本發送到指定的url,然后它會給我們回復翻譯結果,我們可以選擇xml、json等返回格式,我選得是xml,接著,在瀏覽器里面按著指定的格式輸入url,就可以看到返回結果啦:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <youdao-fanyi>  
  3.     <errorCode>0</errorCode>  
  4.     <query><![CDATA[這里是有道翻譯API]]></query>  
  5.     <!-- 有道翻譯 -->  
  6.     <translation>  
  7.             <paragraph><![CDATA[Here is the youdao translation API]]></paragraph>  
  8.         </translation>  
  9. </youdao-fanyi>  
復制代碼

  注意,如果是對詞進行翻譯的話有的詞還會返回一些啥網絡釋義,基本釋義啥的,具體對這個xml解析的方法請看下面的代碼。

  微信公眾帳號

  接著,我們要去微信的公眾帳號平臺去申請一個公眾帳號,不能用現有的已綁定私人微信帳號的QQ號申請,我用的是一個平時不用的QQ號申請的,申請成功后,可以大致看看微信公眾帳號的管理平臺(現在你知道那些公眾帳號,比如王力宏的帳號啥的是怎么運作的了吧),接著去這里仔細閱讀微信公眾帳號自動回復開放接口的文檔,你要從這里學一種如何讓用戶認證的思想(就是如果用戶做了XX,給我返回了XX結果,那么我就能確定,用戶是“合法”的),或者認證的方法。大致有一個認識后,趕緊下載他給的樣例php源碼,也是唯一的可以參考的源碼,仔細閱讀,如下:
  1. <?php  
  2. /** 
  3.   * wechat php test 
  4.   */  
  5.   
  6. //define your token  
  7. define("TOKEN", "weixin");  
  8. $wechatObj = new wechatCallbackapiTest();  
  9. $wechatObj->valid();  
  10.   
  11. class wechatCallbackapiTest  
  12. {  
  13.     public function valid()  
  14.     {  
  15.         $echoStr = $_GET["echostr"];  
  16.   
  17.         //valid signature , option  
  18.         if($this->checkSignature()){  
  19.             echo $echoStr;  
  20.             exit;  
  21.         }  
  22.     }  
  23.   
  24.     public function responseMsg()  
  25.     {  
  26.         //get post data, May be due to the different environments  
  27.         $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];  
  28.   
  29.         //extract post data  
  30.         if (!empty($postStr)){  
  31.        echoStr           
  32.                 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);  
  33.                 $fromUsername = $postObj->FromUserName;  
  34.                 $toUsername = $postObj->ToUserName;  
  35.                 $keyword = trim($postObj->Content);  
  36.                 $time = time();  
  37.                 $textTpl = "<xml>  
  38.                             <ToUserName><![CDATA[%s]]></ToUserName>  
  39.                             <FromUserName><![CDATA[%s]]></FromUserName>  
  40.                             <CreateTime>%s</CreateTime>  
  41.                             <MsgType><![CDATA[%s]]></MsgType>  
  42.                             <Content><![CDATA[%s]]></Content>  
  43.                             <FuncFlag>0</FuncFlag>  
  44.                             </xml>";               
  45.                 if(!empty( $keyword ))  
  46.                 {  
  47.                     $msgType = "text";  
  48.                     $contentStr = "Welcome to wechat world!";  
  49.                     $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);  
  50.                     echo $resultStr;  
  51.                 }else{  
  52.                     echo "Input something...";  
  53.                 }  
  54.   
  55.         }else {  
  56.             echo "";  
  57.             exit;  
  58.         }  
  59.     }  
  60.           
  61.     private function checkSignature()  
  62.     {  
  63.         $signature = $_GET["signature"];  
  64.         $timestamp = $_GET["timestamp"];  
  65.         $nonce = $_GET["nonce"];      
  66.                   
  67.         $token = TOKEN;  
  68.         $tmpArr = array($token, $timestamp, $nonce);  
  69.         sort($tmpArr);  
  70.         $tmpStr = implode( $tmpArr );  
  71.         $tmpStr = sha1( $tmpStr );  
  72.           
  73.         if( $tmpStr == $signature ){  
  74.             return true;  
  75.         }else{  
  76.             return false;  
  77.         }  
  78.     }  
  79. }  
  80.   
  81. ?>  
復制代碼

  很簡單吧,以至于被一些人說寫的很水,但是我覺得,這份php源碼還是很有含金量的;網上一些哥們還抱怨啥啥的直接部署樣例php不能運行啥的,拜托,有點職業精神好不好,連我這個之前完全不會php的人都能看出來要調用里面的responseMsg( )方法才能實現自動回復,樣例里面的只是調用了微信接入的認證功能的函數。
上面的代碼寫的很好,不需要我多解釋,相信大家能看出來它是怎么工作的。
設計與實現
  接著就可以實現我們自己的應用了,首先把我們在SAE上創建的應用通過SVN檢出到本地,然后切換到檢出的目錄,用Django的命令創建一個應用,目錄結構如下:
 

  其中,index.wsgi和config.yaml是SAE規定的文件,具體請仔細閱讀SAE的文檔。
  之后就可以編寫我們自己的服務端代碼了,大致思想就是:用戶A向公眾帳號發送一條消息,微信平臺會按著公眾帳號預先的設置,把用戶A的消息內容和一些其他信息(如創建時間等)以xml的形式post到我們預先設置好的url上(這個url的服務端就是我們要寫的在SAE上的應用),我們要做的就是每當接受到微信post請求,我們解析微信平臺post過來的xml,得到用戶A的消息內容,把消息內容以get的形式發送到有道API,獲取有道API返回的xml(或json等),解析,之后按微信平臺規定的格式構造成一個xml,作為微信平臺post請求的結果給其返回,微信平臺收到結果后,會把消息自動回復給用戶,用戶就能收到翻譯結果了。
  用一個圖表示上述過程如下:
 

源碼
  下面貼出邏輯處理部分代碼如下(Views.py),各函數功能不言而喻:
  1. [python] view plaincopy
  2. # -*- coding: utf-8 -*-  
  3. from django.http import HttpResponse  
  4. from django.template import RequestContext, Template  
  5. from django.views.decorators.csrf import csrf_exempt  
  6. from django.utils.encoding import smart_str, smart_unicode  
  7.   
  8. import xml.etree.ElementTree as ET  
  9. import urllib,urllib2,time,hashlib  
  10.   
  11. TOKEN = "你設置的Token"  
  12.   
  13. YOUDAO_KEY = 你申請到的有道的Key  
  14. YOUDAO_KEY_FROM = "有道的key-from"  
  15. YOUDAO_DOC_TYPE = "xml"  

  16. @csrf_exempt  
  17. def handleRequest(request):  
  18.     if request.method == 'GET':  
  19.         #response = HttpResponse(request.GET['echostr'],content_type="text/plain")  
  20.         response = HttpResponse(checkSignature(request),content_type="text/plain")  
  21.         return response  
  22.     elif request.method == 'POST':  
  23.         #c = RequestContext(request,{'result':responseMsg(request)})  
  24.         #t = Template('{{result}}')  
  25.         #response = HttpResponse(t.render(c),content_type="application/xml")  
  26.         response = HttpResponse(responseMsg(request),content_type="application/xml")  
  27.         return response  
  28.     else:  
  29.         return None  
  30.   
  31. def checkSignature(request):  
  32.     global TOKEN  
  33.     signature = request.GET.get("signature", None)  
  34.     timestamp = request.GET.get("timestamp", None)  
  35.     nonce = request.GET.get("nonce", None)  
  36.     echoStr = request.GET.get("echostr",None)  
  37.   
  38.     token = TOKEN  
  39.     tmpList = [token,timestamp,nonce]  
  40.     tmpList.sort()  
  41.     tmpstr = "%s%s%s" % tuple(tmpList)  
  42.     tmpstr = hashlib.sha1(tmpstr).hexdigest()  
  43.     if tmpstr == signature:  
  44.         return echoStr  
  45.     else:  
  46.         return None  
  47.   
  48. def responseMsg(request):  
  49.     rawStr = smart_str(request.raw_post_data)  
  50.     #rawStr = smart_str(request.POST['XML'])  
  51.     msg = paraseMsgXml(ET.fromstring(rawStr))  
  52.       
  53.     queryStr = msg.get('Content','You have input nothing~')  
  54.   
  55.     raw_youdaoURL = "http://fanyi.youdao.com/openapi.do?keyfrom=%s&key=%s&type=data&doctype=%s&version=1.1&q=" % (YOUDAO_KEY_FROM,YOUDAO_KEY,YOUDAO_DOC_TYPE)     
  56.     youdaoURL = "%s%s" % (raw_youdaoURL,urllib2.quote(queryStr))  
  57.   
  58.     req = urllib2.Request(url=youdaoURL)  
  59.     result = urllib2.urlopen(req).read()  
  60.   
  61.     replyContent = paraseYouDaoXml(ET.fromstring(result))  
  62.   
  63.     return getReplyXml(msg,replyContent)  
  64.   
  65. def paraseMsgXml(rootElem):  
  66.     msg = {}  
  67.     if rootElem.tag == 'xml':  
  68.         for child in rootElem:  
  69.             msg[child.tag] = smart_str(child.text)  
  70.     return msg  
  71.   
  72. def paraseYouDaoXml(rootElem):  
  73.     replyContent = ''  
  74.     if rootElem.tag == 'youdao-fanyi':  
  75.         for child in rootElem:  
  76.             # 錯誤碼  
  77.             if child.tag == 'errorCode':  
  78.                 if child.text == '20':  
  79.                     return 'too long to translate\n'  
  80.                 elif child.text == '30':  
  81.                     return 'can not be able to translate with effect\n'  
  82.                 elif child.text == '40':  
  83.                     return 'can not be able to support this language\n'  
  84.                 elif child.text == '50':  
  85.                     return 'invalid key\n'  
  86.   
  87.             # 查詢字符串  
  88.             elif child.tag == 'query':  
  89.                 replyContent = "%s%s\n" % (replyContent, child.text)  
  90.   
  91.             # 有道翻譯  
  92.             elif child.tag == 'translation':   
  93.                 replyContent = '%s%s\n%s\n' % (replyContent, '-' * 3 + u'有道翻譯' + '-' * 3, child[0].text)  
  94.   
  95.             # 有道詞典-基本詞典  
  96.             elif child.tag == 'basic':   
  97.                 replyContent = "%s%s\n" % (replyContent, '-' * 3 + u'基本詞典' + '-' * 3)  
  98.                 for c in child:  
  99.                     if c.tag == 'phonetic':  
  100.                         replyContent = '%s%s\n' % (replyContent, c.text)  
  101.                     elif c.tag == 'explains':  
  102.                         for ex in c.findall('ex'):  
  103.                             replyContent = '%s%s\n' % (replyContent, ex.text)  
  104.   
  105.             # 有道詞典-網絡釋義  
  106.             elif child.tag == 'web':   
  107.                 replyContent = "%s%s\n" % (replyContent, '-' * 3 + u'網絡釋義' + '-' * 3)  
  108.                 for explain in child.findall('explain'):  
  109.                     for key in explain.findall('key'):  
  110.                         replyContent = '%s%s\n' % (replyContent, key.text)  
  111.                     for value in explain.findall('value'):  
  112.                         for ex in value.findall('ex'):  
  113.                             replyContent = '%s%s\n' % (replyContent, ex.text)  
  114.                     replyContent = '%s%s\n' % (replyContent,'--')  
  115.     return replyContent  
  116.   
  117. def getReplyXml(msg,replyContent):  
  118.     extTpl = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content><FuncFlag>0</FuncFlag></xml>";  
  119.     extTpl = extTpl % (msg['FromUserName'],msg['ToUserName'],str(int(time.time())),'text',replyContent)  
  120.     return extTpl  
復制代碼

  之后通過SVN把項目部署到SAE上,就OK啦~
遇到的問題
  現在網上這種參考的代碼還很少,在SAE上部署調試也非常困難,無奈下我自己寫了個腳本,模仿微信平臺給自己部署在SAE上的服務端POST消息,看返回的結果。如果出現錯誤,Django都會產生一個優美的錯誤頁面,獲取這個錯誤頁面把它寫到本地的一個html里面,用瀏覽器打開就可以知道是什么錯誤了。
寫的過程中還是遇到不少問題的:
1.Django的CSRF錯誤:
我用的Django 1.4,我嘗試了大家說的很多解決辦法都會出現403錯誤,無奈下只能暫時通過修飾符把Django的CSRF暫時禁掉,這個還要以后學Django的深入調研一下;
2.Django的編碼錯誤:
我也嘗試了很多方法,但是都不行,主要是中文處理上,遇到了很多麻煩,最終在這里找到了完美的解決方案,用可愛的Django自帶的可愛的方法:smart_str、smart_unicode,就能完美處理中文了。
海南網站建設|海南網站制作|海口網站建設|三亞網站建設|儋州網站建設|五指山網站建設|文昌網站建設|瓊海網站建設|萬寧網站建設|東方網站建設|定安網站建設|屯昌網站建設|澄邁網站建設|臨高網站建設|白沙網站建設|昌江網站建設|樂東網站建設|陵水網站建設|保亭網站建設|瓊中網站建設|海口精英網|三亞精英網|文昌精英網|瓊海精英網|陵水精英網|儋州精英網|萬寧精英網|澄邁精英網|海微通
合作伙伴 企業發展 企業文化 聯系我們 在線訂購 網站地圖 返回首頁手機版
海口世紀華聯科技有限公司2020版權所有 24小時服務熱線:13807590485   歡迎來電咨詢
地址:海南省.海口市.海甸二東路環惠大廈6樓(南寶路明都大廈107#) 公司電話:0898-31568080 31568060 QQ:85398489
全國合作聯盟分布:海南海口 四川成都 湖北武漢 湖南長沙 安徽合肥 廣東深圳 山西太原 西藏拉薩
技術服務: E_mail:server@web0898.net 服務訂購:E_mail:server@web0898.net 在線客服邀請 瓊ICP備10201086號-9
推廣關鍵字:海南網站建設,海南網站制作,海南網站開發,海南微信開發,海南微信公眾號開發,海南微信公眾號代運營,海南模板網站制作,海南網頁設計,海南網絡公司
(*^▽^*)MG特工简.布隆德归来在线客服 五期内必开三中三 天天贵阳麻将 宁夏十一选五前三组走势图 网上哪里能买到青海快3 幸运飞艇是私彩吗 博远棋牌 湖北红中赖子麻将打法 成都麻将技巧必胜绝 宝马线上娱乐手机登录 河北十一选五开奖查询 福建36选7开奖查询 三分彩免费计划 大嘴棋牌手机版 游戏 上海哈灵麻将下载2019 18号nba掘金vs爵士比赛 秒速时时彩盛世官网