Python微信公众号开发平台的示例分析(python,开发技术)

时间:2024-05-06 17:44:04 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

Python微信公众号开发平台的示例分析

上大学的时候,对微信公众号开发浅尝辄止的玩了一下,感觉还是挺有意思的。

https://www.jb51.net/article/133677.htm后来服务器到期了,也就搁置了。由于发布web程序,使用PHP很顺手,就使用了PHP作为开发语言。但是其实微信公众号的开发和语言关联并不大,流程,原理上都是一致的。

快要做毕设了,想着到时候应该会部署一些代码到服务器上,进行长期的系统构建。所以趁着还是学生,就买了阿里云的学生机。买了之后,就想着玩点什么,于是微信公众号的开发,就又提上了日程。但是这次,我不打算使用PHP了,感觉局限性相对于Python而言,稍微有点大。

使用Python的话,可以灵活的部署一些爬虫类程序,和用户交互起来也会比较方便。可拓展性感觉也比较的高,于是就选它了。

服务器配置这部分属于是比较基础的,不太明白的可以看看我之前的那个博客,还算是比较的详细。今天就只是对核心代码做下介绍好了。

项目目录

root@aliyun:/var/www/html/wx/py#ls*.pyapi.pydispatcher.pyrobot.pyroot@aliyun:/var/www/html/wx/py#

api.py

这个文件相当于是一个关卡,涉及token的验证,和服务的支持。

#-*-coding:utf-8-*-#中文编码importsysreload(sys)#不加这部分处理中文还是会出问题sys.setdefaultencoding('utf-8')importtimefromflaskimportFlask,request,make_responseimporthashlibimportjsonimportxml.etree.ElementTreeasETfromdispatcherimport*app=Flask(__name__)app.debug=True@app.route('/')#默认网址defindex():return'IndexPage'@app.route('/wx',methods=['GET','POST'])defwechat_auth():#处理微信请求的处理函数,get方法用于认证,post方法取得微信转发的数据ifrequest.method=='GET':token='你自己设置好的token'data=request.argssignature=data.get('signature','')timestamp=data.get('timestamp','')nonce=data.get('nonce','')echostr=data.get('echostr','')s=[timestamp,nonce,token]s.sort()s=''.join(s)if(hashlib.sha1(s).hexdigest()==signature):returnmake_response(echostr)else:rec=request.stream.read()#接收消息dispatcher=MsgDispatcher(rec)data=dispatcher.dispatch()withopen("./debug.log","a")asfile:file.write(data)file.close()response=make_response(data)response.content_type='application/xml'returnresponseif__name__=='__main__':app.run(host="0.0.0.0",port=80)

dispatcher.py

这个文件是整个服务的核心,用于识别用户发来的消息类型,然后交给不同的handler来处理,并将运行的结果反馈给前台,发送给用户。消息类型这块,在微信的开发文档上有详细的介绍,因此这里就不再过多的赘述了。

#!/usr/binpython#coding:utf8importsysreload(sys)sys.setdefaultencoding("utf8")importtimeimportjsonimportxml.etree.ElementTreeasETfromrobotimport*classMsgParser(object):"""用于解析从微信公众平台传递过来的参数,并进行解析"""def__init__(self,data):self.data=datadefparse(self):self.et=ET.fromstring(self.data)self.user=self.et.find("FromUserName").textself.master=self.et.find("ToUserName").textself.msgtype=self.et.find("MsgType").text#纯文字信息字段self.content=self.et.find("Content").textifself.et.find("Content")isnotNoneelse""#语音信息字段self.recognition=self.et.find("Recognition").textifself.et.find("Recognition")isnotNoneelse""self.format=self.et.find("Format").textifself.et.find("Format")isnotNoneelse""self.msgid=self.et.find("MsgId").textifself.et.find("MsgId")isnotNoneelse""#图片self.picurl=self.et.find("PicUrl").textifself.et.find("PicUrl")isnotNoneelse""self.mediaid=self.et.find("MediaId").textifself.et.find("MediaId")isnotNoneelse""#事件self.event=self.et.find("Event").textifself.et.find("Event")isnotNoneelse""returnselfclassMsgDispatcher(object):"""根据消息的类型,获取不同的处理返回值"""def__init__(self,data):parser=MsgParser(data).parse()self.msg=parserself.handler=MsgHandler(parser)defdispatch(self):self.result=""#统一的公众号出口数据ifself.msg.msgtype=="text":self.result=self.handler.textHandle()elifself.msg.msgtype=="voice":self.result=self.handler.voiceHandle()elifself.msg.msgtype=='image':self.result=self.handler.imageHandle()elifself.msg.msgtype=='video':self.result=self.handler.videoHandle()elifself.msg.msgtype=='shortvideo':self.result=self.handler.shortVideoHandle()elifself.msg.msgtype=='location':self.result=self.handler.locationHandle()elifself.msg.msgtype=='link':self.result=self.handler.linkHandle()elifself.msg.msgtype=='event':self.result=self.handler.eventHandle()returnself.resultclassMsgHandler(object):"""针对type不同,转交给不同的处理函数。直接处理即可"""def__init__(self,msg):self.msg=msgself.time=int(time.time())deftextHandle(self,user='',master='',time='',content=''):template="""<xml><ToUserName><![CDATA[{}]]></ToUserName><FromUserName><![CDATA[{}]]></FromUserName><CreateTime>{}</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[{}]]></Content></xml>"""#对用户发过来的数据进行解析,并执行不同的路径try:response=get_response_by_keyword(self.msg.content)ifresponse['type']=="image":result=self.imageHandle(self.msg.user,self.msg.master,self.time,response['content'])elifresponse['type']=="music":data=response['content']result=self.musicHandle(data['title'],data['description'],data['url'],data['hqurl'])elifresponse['type']=="news":items=response['content']result=self.newsHandle(items)#这里还可以添加更多的拓展内容else:response=get_turing_response(self.msg.content)result=template.format(self.msg.user,self.msg.master,self.time,response)#withopen("./debug.log",'a')asf:#f.write(response['content']+'~~'+result)#f.close()exceptExceptionase:withopen("./debug.log",'a')asf:f.write("texthandler:"+str(e.message))f.close()returnresultdefmusicHandle(self,title='',description='',url='',hqurl=''):template="""<xml><ToUserName><![CDATA[{}]]></ToUserName><FromUserName><![CDATA[{}]]></FromUserName><CreateTime>{}</CreateTime><MsgType><![CDATA[music]]></MsgType><Music><Title><![CDATA[{}]]></Title><Description><![CDATA[{}]]></Description><MusicUrl><![CDATA[{}]]></MusicUrl><HQMusicUrl><![CDATA[{}]]></HQMusicUrl></Music><FuncFlag>0</FuncFlag></xml>"""response=template.format(self.msg.user,self.msg.master,self.time,title,description,url,hqurl)returnresponsedefvoiceHandle(self):response=get_turing_response(self.msg.recognition)result=self.textHandle(self.msg.user,self.msg.master,self.time,response)returnresultdefimageHandle(self,user='',master='',time='',mediaid=''):template="""<xml><ToUserName><![CDATA[{}]]></ToUserName><FromUserName><![CDATA[{}]]></FromUserName><CreateTime>{}</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[{}]]></MediaId></Image></xml>"""ifmediaid=='':response=self.msg.mediaidelse:response=mediaidresult=template.format(self.msg.user,self.msg.master,self.time,response)returnresultdefvideoHandle(self):return'video'defshortVideoHandle(self):return'shortvideo'deflocationHandle(self):return'location'deflinkHandle(self):return'link'defeventHandle(self):return'event'defnewsHandle(self,items):#图文消息这块真的好多坑,尤其是<![CDATA[]]>中间不可以有空格,可怕极了articlestr="""<item><Title><![CDATA[{}]]></Title><Description><![CDATA[{}]]></Description><PicUrl><![CDATA[{}]]></PicUrl><Url><![CDATA[{}]]></Url></item>"""itemstr=""foriteminitems:itemstr+=str(articlestr.format(item['title'],item['description'],item['picurl'],item['url']))template="""<xml><ToUserName><![CDATA[{}]]></ToUserName><FromUserName><![CDATA[{}]]></FromUserName><CreateTime>{}</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>{}</ArticleCount><Articles>{}</Articles></xml>"""result=template.format(self.msg.user,self.msg.master,self.time,len(items),itemstr)returnresult

robot.py

这个文件属于那种画龙点睛性质的。

#!/usr/binpython#coding:utf8importrequestsimportjsondefget_turing_response(req=""):url="http://www.tuling123.com/openapi/api"secretcode="嘿嘿,这个就不说啦"response=requests.post(url=url,json={"key":secretcode,"info":req,"userid":12345678})returnjson.loads(response.text)['text']ifresponse.status_code==200else""defget_qingyunke_response(req=""):url="http://api.qingyunke.com/api.php?key=free&appid=0&msg={}".format(req)response=requests.get(url=url)returnjson.loads(response.text)['content']ifresponse.status_code==200else""#简单做下。后面慢慢来defget_response_by_keyword(keyword):if'团建'inkeyword:result={"type":"image","content":"3s9Dh6rYdP9QruoJ_M6tIYDnxLLdsQNCMxkY0L2FMi6HhMlNPlkA1-50xaE_imL7"}elif'music'inkeywordor'音乐'inkeyword:musicurl='http://204.11.1.34:9999/dl.stream.qqmusic.qq.com/C400001oO7TM2DE1OE.m4a?vkey=3DFC73D67AF14C36FD1128A7ABB7247D421A482EBEDA17DE43FF0F68420032B5A2D6818E364CB0BD4EAAD44E3E6DA00F5632859BEB687344&guid=5024663952&uin=1064319632&fromtag=66'result={"type":"music","content":{"title":"80000","description":"有个男歌手姓巴,他的女朋友姓万,于是这首歌叫80000","url":musicurl,"hqurl":musicurl}}elif'关于'inkeyword:items=[{"title":"关于我","description":"喜欢瞎搞一些脚本","picurl":"https://avatars1.githubusercontent.com/u/12973402?s=460&v=4","url":"https://github.com/guoruibiao"},{"title":"我的博客","description":"收集到的,瞎写的一些博客","picurl":"http://avatar.csdn.net/0/8/F/1_marksinoberg.jpg","url":"http://blog.csdn.net/marksinoberg"},{"title":"薛定谔的:dog:","description":"副标题有点奇怪,不知道要怎么设置比较好","picurl":"https://www.baidu.com/img/bd_logo1.png","url":"http://www.baidu.com"}]result={"type":"news","content":items}else:result={"type":"text","content":"可以自由进行拓展"}returnresult

其实这看起来是一个文件,其实可以拓展为很多的方面。

如果想通过公众号来监控服务器的运行情况,就可以添加一个对服务器负载的监控的脚本;

如果想做一些爬虫,每天抓取一些高质量的文章,然后通过公众号进行展示。

不方便使用电脑的情况下,让公众号调用一些命令也可以算是曲线救国的一种方式。

等等吧,其实有多少想法,就可以用Python进行事先。然后通过公众号这个平台进行展示。

易错点

在从PHP重构为Python的过程中,我其实也是遇到了一些坑的。下面总结下,如果恰好能帮助到遇到同样问题的你,那我这篇文章也算是没有白写了。

微信公众号的开发,其实关键就在于理解这个工作的模式。大致有这么两条路。

用户把消息发送到微信公众平台上,平台把信息拼接组装成XML发到我们自己的服务器。(通过一系列的认证,校验,让平台知道,我们的服务是合法的),然后服务器将XML进行解析,处理。

我们的服务器解析处理完成后,将数据再次拼接组装成XML,发给微信公众平台,平台帮我们把数据反馈给对应的用户。
这样,一个交互就算是完成了。在这个过程中,有下面几个容易出错的地方。

token校验: token的校验是一个get方式的请求。通过代码我们也可以看到,就是对singature的校验,具体看代码就明白了。

XML数据的解析,对于不同的消息,记得使用不同的格式。其中很容易出错的就是格式不规范。 <!CDATA[[]]> 中括号之间最好不要有空格,不然定位起错误还是很麻烦的。

服务的稳定性。这里用的web框架是flask,小巧精良。但是对并发的支持性不是很好,对此可以使用uwsgi和Nginx来实现一个更稳定的服务。如果就是打算自己玩一玩,通过命令行启用(如python api.py)就不是很保险了,因为很有可能会因为用户的一个奇怪的输入导致整个服务垮掉,建议使用nohup的方式,来在一定程度上保证服务的质量。

结果演示

目前这个公众号支持文字,语音,图片,图文等消息类型。示例如下。

Python微信公众号开发平台的示例分析

Python微信公众号开发平台的示例分析

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Python微信公众号开发平台的示例分析的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:怎么搭建vue2.0+boostrap项目下一篇:

2 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18