[python]用flask框架搭建微信公众号的后台
创始人
2024-04-04 18:00:06

用flask框架搭建微信公众号的后台

最近用python写了点爬虫,为了要让爬取的数据能够随时显示在我眼前,并实时根据我的指令返回数据。于是采用微信公众号做这个显示窗口,既能发送指令也能显示简单的相关数据。

准备工具
  • python3.x环境

  • pycharm

  • 一台服务器(可以使用内网穿透)

  • 申请一个微信公众号

一、搭建微信公众号后台

查看公众号

​ 登录公众号平台,在基础配置中设置相关信息,点提交时微信会访问我设置的接口,如果我返回了正确的信息,那我的公众号就与我的这个接口绑定上了,之后微信所有的消息都将通过调用我的这个接口来与我的服务器交互。现在提交肯定是失败的,我还没有配置后端,自然是请求不到,且看我下面的操作。

image-20221106112648079

使用flask框架搭建一个后端服务器

​ 创建app.py,然后通过flask搭建后端服务器,这里的代码是完整代码,其中WxHandle是响应微信请求的具体实现。这个项目一直监听的是8800端口,但我后面会用nginx反向代理一波。

app.py

from flask import Flask, request
from loguru import loggerfrom wx_handler import WxHandle# 配置web框架
app = Flask(__name__)
# 日志文件保存10天日志,最大存储500M
logger.add("./log/runtime_{time}.log", retention="10 days", rotation="500 MB")# 暴露路由,接收get和post请求
@app.route('/', methods=["GET", "POST"])
def wx_listener():# 通过getattr获取到WxHandle的静态get或post方法,lower是为了将大写method值转为小写,与WxHandle中的方法名对应fun = getattr(WxHandle, request.method.lower())# 调用得到的get或post方法return fun()if __name__ == "__main__":# 监听8800端口app.run(host="0.0.0.0", port=8880)
WxHandle的具体实现

​ WxHandle是响应微信消息的具体入口,所有的请求都或通过post或get方法来得到回复。这其中的签名算法和具体消息对象也会在下面体现。

wx_handle.py

from flask import request
from loguru import loggerfrom wx.verification import signature as f_signature	# 签名算法
import wx.receive as receive	# 接收微信消息的地形
import wx.reply as reply		# 将要答复的信息包装成微信需要的xml格式class WxHandle:@staticmethoddef post():"""响应微信的post请求,微信用户发送的信息会使用Post请求:return:"""try:logger.info("接收微信消息->\n"+str(request.data))# 对微信传来的xml信息进行解析,解析成我们自定义的对象信息receive_msg = receive.parse_xml(request.data)# 如果解析成功if isinstance(receive_msg, receive.Msg):# 该微信信息为文本信息if receive_msg.type == "text":# 创建一条文本信息准备返回给微信,文本内容为“测试”msg = reply.TextMsg(receive_msg, "测试")# 发送我创建的文本信息return msg.send()else:# 该信息不为文本信息时,发送我定义好的一条文本信息给他return reply.Msg(receive_msg).send()except Exception:logger.error("解析微信XML数据失败!")return "xml解析出错"@staticmethoddef get():"""响应微信的get请求,微信的验证信息会使用get请求这里的验证方式是按照微信公众号文档上的教程来做的:return: """# 微信传来的签名,需要和我生成的签名进行比对signature = request.args.get('signature')   # 微信已经加密好的签名,供我比对用timestamp = request.args.get('timestamp')   # 这是我需要的加密信息nonce = request.args.get('nonce')           # 也是需要的加密信息# 判断该请求是否正常,签名是否匹配try:# 微信传来的签名与我加密的签名进行比对,成功则返回指定数据给微信if signature == f_signature(timestamp, nonce):# 微信要求比对成功后返回他传来的echost数据给他return request.args.get('echostr')else:return ""except Exception:logger.error("签名失败!")return "签名失败!"
signature签名算法的具体实现

​ 这是根据微信要求编写的签名算法,目的是于微信传来的签名进行比对,以此来保证请求的正确性。

wx/verification.py

import hashlib
TOKEN = "kuiming"   # 这个token要与我在微信公众号上设置的token是一样的def signature(timestamp, nonce):"""根据微信公众号文档写的微信需要的签名算法:param timestamp::param nonce::return:"""# 接收微信服务器传来的时间戳和随机值,与我们自己设定的Token值进行排序后组成一个字符串signature_list = [TOKEN, timestamp, nonce]# 对列表进行排序signature_list.sort()# 组成字符串ciphertext = "".join(signature_list)# 进行sha1算法加密sha1 = hashlib.sha1()# python3.x后的算法写法sha1.update(ciphertext.encode("utf-8"))# 返回加密后的签名return sha1.hexdigest()
消息接收类与消息响应类

​ 为了降低模块间的耦合性,我将消息类拆分为接收消息类和响应消息类。接收消息类会接收微信发来的消息,并将它解析为对象,这样可以方便我们之后的操作。回复消息类是将我们想要回复给用户的消息又打包为一个xml格式的微信消息包,然后再通过WxHandle中的接口信息返回回去,形成一个有效交互。

wx/receive.py

from lxml import etree	# 用来解析xml格式的数据的库def parse_xml(web_data):"""解析微信传递来的消息,根据消息类型转换为不同的对象:param web_data::return:"""# 解析xml数据xml = etree.XML(web_data)# 查看消息类型msg_type = xml.find('MsgType').textif msg_type == 'text':# 为文本时生成文本对象return TextMsg(xml)elif msg_type == 'image':# 为图像是生成图像对象return ImageMsg(xml)return Noneclass Msg:"""定义消息的基本格式,是一些类型消息的父类,解析XML格式的微信信息"""def __init__(self, xml):self.toUser = xml.find('ToUserName').text   # 公众号的微信号self.fromUser = xml.find('FromUserName').text   # 发送消息的用户的openidself.time = xml.find('CreateTime').text     # 创建时间self.type = xml.find('MsgType').text        # 消息类型self.id = xml.find('MsgId').text            # 该消息的id,每天消息都有独立的idclass TextMsg(Msg):"""解析文字类信息"""def __init__(self, xml):Msg.__init__(self, xml)     # 为父类的属性赋值self.content = xml.find('Content').text.encode("utf-8")     # 传递来的信息需要经过utf-8编码class ImageMsg(Msg):"""解析图片信息"""def __init__(self, xml):Msg.__init__(self, xml)self.picUrl = xml.find('PicUrl').textself.mediaId = xml.find('MediaId').text

wx/reply.py

​ 这里要非常注意,回复消息的发送者是我们自己,而接收消息者是用户,所以必须把我们接受到的微信消息的接收者和发送者调换一下才能正确回复。

import time
import wx.receive as receiveclass Msg:def __init__(self, receive_msg: receive.Msg):"""将回复用户的信息按照微信的xml格式进行包装:param receive_msg: """self.dict = dict()# 这里是我发送信息,所以发送给我们收到的微信消息的发送者self.dict['ToUserName'] = receive_msg.fromUser# 而是谁发送的呢?自然是我们收到的微信消息的接收者,也就是我的公众号self.dict['FromUserName'] = receive_msg.toUser# 发送时间self.dict['CreateTime'] = int(time.time())# 发送的信息文本,这里是默认的文本self.dict['Content'] = "对不起,我没有看懂你的信息~"passdef send(self):# 发送的xml格式xml = """{CreateTime}"""# 将当前对象的dict属性填入到xml文本中,对应的{ToUserName}、{FromUserName}等return xml.format(**self.dict)class TextMsg(Msg):def __init__(self, receive_msg: receive.Msg, content):super().__init__(receive_msg)self.dict['Content'] = contentdef send(self):xml = """{CreateTime}"""return xml.format(**self.dict)class ImageMsg(Msg):def __init__(self, receive_msg: receive.Msg, media_id):super().__init__(receive_msg)self.dict['MediaId'] = media_iddef send(self):xml = """{CreateTime}"""return xml.format(**self.dict)

二、部署到服务器

准备

​ 整个部署操作我不会使用shell命令,而是通过部署在服务器中的宝塔面板自动完成。

将项目移动到服务器

​ 这里通过宝塔面板直接把项目拖到了指定目录里

image-20221106125950927

使用宝塔应用管理器启动应用

​ 在宝塔面板的软件商店里下载宝塔应用管理器,用来管理和运行项目

image-20221106130327514

image-20221106130445579

配置nginx反向代理

​ 当项目启动后监听的是8800端口,并且还是http协议。而我配置nginx会把所有http协议的请求转为https协议,这会导致找不到这个接口。于是为了接口美观和正常使用,我将其代理到433端口下的/wx_zhuxuebao路由下,这也是为什么我第一张图中配置的URL中设置的是/wx_zhuxuebao了。

image-20221106131000117

完成

​ 到这里最基础的项目就部署好了,下一步准备在微信中进行测试。

三、测试

成功实现了我期待的效果,其中返回**”测试“**是因为在WxHandle类的post方法中判断如果是文字则

# 创建一条文本信息准备返回给微信,文本内容为“测试”
msg = reply.TextMsg(receive_msg, "测试")
# 发送我创建的文本信息
return msg.send()

返回**”对不起,我没有看懂你的信息~“**是因为在WxHandle类的post方法中判断如果不是文字则

else:# 该信息不为文本信息时,发送我定义好的一条文本信息给他return reply.Msg(receive_msg).send()

Msg类中存在Content属性

# 发送的信息文本,这里是默认的文本
self.dict['Content'] = "对不起,我没有看懂你的信息~"
测试截图

image-20221106131641934

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...