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

news2024/11/27 14:29:52

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

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

准备工具
  • python3.x环境

  • pycharm

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

  • 申请一个微信公众号

一、搭建微信公众号后台

查看公众号

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

image-20221106112648079

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

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

app.py

from flask import Flask, request
from loguru import logger

from 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 logger

from wx.verification import signature as f_signature	# 签名算法
import wx.receive as receive	# 接收微信消息的地形
import wx.reply as reply		# 将要答复的信息包装成微信需要的xml格式


class WxHandle:

    @staticmethod
    def 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解析出错"

    @staticmethod
    def 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').text
    if msg_type == 'text':
        # 为文本时生成文本对象
        return TextMsg(xml)
    elif msg_type == 'image':
        # 为图像是生成图像对象
        return ImageMsg(xml)
    return None


class Msg:
    """
    定义消息的基本格式,是一些类型消息的父类,解析XML格式的微信信息
    """
    def __init__(self, xml):
        self.toUser = xml.find('ToUserName').text   # 公众号的微信号
        self.fromUser = xml.find('FromUserName').text   # 发送消息的用户的openid
        self.time = xml.find('CreateTime').text     # 创建时间
        self.type = xml.find('MsgType').text        # 消息类型
        self.id = xml.find('MsgId').text            # 该消息的id,每天消息都有独立的id


class 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').text
        self.mediaId = xml.find('MediaId').text

wx/reply.py

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

import time
import wx.receive as receive


class 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'] = "对不起,我没有看懂你的信息~"
        pass

    def send(self):
        # 发送的xml格式
        xml = """
                    <xml>
                        <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
                        <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
                        <CreateTime>{CreateTime}</CreateTime>
                        <MsgType><![CDATA[text]]></MsgType>
                        <Content><![CDATA[{Content}]]></Content>
                    </xml>
              """
        # 将当前对象的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'] = content

    def send(self):
        xml = """
            <xml>
                <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
                <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
                <CreateTime>{CreateTime}</CreateTime>
                <MsgType><![CDATA[text]]></MsgType>
                <Content><![CDATA[{Content}]]></Content>
            </xml>
            """
        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_id

    def send(self):
        xml = """
            <xml>
                <ToUserName><![CDATA[{ToUserName}]]></ToUserName>
                <FromUserName><![CDATA[{FromUserName}]]></FromUserName>
                <CreateTime>{CreateTime}</CreateTime>
                <MsgType><![CDATA[image]]></MsgType>
                <Image>
                <MediaId><![CDATA[{MediaId}]]></MediaId>
                </Image>
            </xml>
            """
        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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3与vue2的不同内容

一、main.js入口文件的不同 // 引入的不再是构造函数&#xff0c;引入了一个名为creacteApp的工厂函数 import { createApp } from vue import ./style.css import App from ./App.vue // 创建应用示例对象--->app const app createApp(App) //把组件APP挂载到#app节点上 …

疫情可视化(后续)

前言 这是疫情可视化最开始的文章&#xff0c;有需要了解的可前往查看&#xff1a;https://blog.csdn.net/xi1213/article/details/126824752。 本来说有时间就把这个项目完结了的&#xff0c;结果后面一直有事拖着&#xff0c;直到现在十一月份了才搞完。老样子&#xff0c;先…

拓端tecdat|R语言代做时间序列和ARIMA模型预测拖拉机销售的制造案例研究

全文链接&#xff1a;http://tecdat.cn/?p5421 原文出处&#xff1a;拓端数据部落公众号 相关视频&#xff1a;在Python和R语言中建立EWMA&#xff0c;ARIMA模型预测时间序列 本文是我们通过时间序列和ARIMA模型预测拖拉机销售的制造案例研究示例的延续。您可以在以下链接中找…

2023第二届中国绿色包装创新峰会|低碳与数字化时代的绿色包装

峰会背景 随着中国市场包装使用量的激增&#xff0c;中国已成为全球最大的包装市场&#xff0c;环境中废弃包装所导致的生态负担也同步加剧。但随着消费者可持续发展意识的显著增强&#xff0c;企业环保意识的提升以及国家强制性环保政策的出台&#xff0c;包装可持续发展变得…

初识C++(三)

概述&#xff1a;本篇主要讲述“引用“ 分别就引用的概念、引用特性、引用的应用场景、以及常引用展开描述。后续会补充引用的底层原理&#xff0c;敬请期待。 目录 什么是引用&#xff1f; 引用的三个特性 引用的应用 引用做参数 引用做返回值 常引用 总结 什么是引用&a…

计算机毕业设计(附源码)python智慧停车系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

纸牌游戏设计制作《摸鱼2》(C语言)

纸牌游戏设计制作《摸鱼2》 此游戏设计属于简单的纸牌游戏&#xff0c;是儿童益智类游戏。适用于儿童的认知教育。 游戏规则极为简单&#xff0c;设置纸牌在界面上显示牌背的盲牌形式&#xff0c;点击牌背显示牌面找出相同的牌配对消牌。 这设置主要培养儿童的心理素质&#x…

Arduino WIFI智能小车 无线视频遥控小车(论文+程序+原理图+驱动+安装手册等)

目录 一、项目产生的背景分析 2 1.1项目想法 2 1.2用户将如何从产品中获益 2-3 二、方案设计 3 2.1小车整体系统 2-3 2.2小车部件介绍 3-5 三、小车组装 6 3.1小车配件购置 6 3.2小车部件组装 7-10 3.3小车程序代码的调试 11 3.3.1小车驱动安装 11 3.3.2小车编程环境&#xff0…

K线形态识别_倒锤头线和射击之星(流星、扫帚星)

写在前面&#xff1a; 1. 本文中提到的“K线形态查看工具”的具体使用操作请查看该博文&#xff1b; 2. K线形体所处背景&#xff0c;诸如处在上升趋势、下降趋势、盘整等&#xff0c;背景内容在K线形态策略代码中没有体现&#xff1b; 3. 文中知识内容来自书籍《K线技术分析》…

R语言—基本统计分析

文章目录基本统计分析1基本方法summary()函数apply()函数lapply()函数sapply()函数2.常见的描述指标标准误binom.test (二项分布精确检验)变异系数极差偏度系数&#xff08;skewness&#xff09;3分组计算描述性统计量aggregate()函数by()函数频数表和列联表列联表生成频数表一…

STM32F103VET6基于STM32CubeMX创建定时器中断控制LED闪烁

STM32F103VET6基于STM32CubeMX创建定时器中断控制LED闪烁&#x1f33c;STM32CubeMX配置界面演示 ⚡需求是通过定时器1来控制LED灯1s亮灭。 &#x1f4cc;工程分为两部分组成&#xff1a;STM32CubeMX创建并配置工程和业务代码完善 &#x1f341;STM32CubeMX创建并配置工程 1.…

用Python实现的这五个小游戏,你真的学会了嘛?

游戏名称1、五子棋 2、雷霆战机 3、贪吃蛇 4、坦克大战 5、俄罗斯方块 开发环境 Python版本&#xff1a;3.6.4 相关模块&#xff1a; pygame模块&#xff1b; 以及一些Python自带的模块。 环境搭建 安装Python并添加到环境变量&#xff0c;pip安装需要的相关模块即可。 一&am…

【博学谷学习记录】超强总结,用心分享|Hive表生成函数

文章目录explode函数Array类型数据演示演示数据创建一张包含array类型的表插入表数据查询验证使用explode查询Map 类型数据演示演示数据创建一张包含map类型的表加载表数据查询验证使用explode查询later view侧视图关键字演示数据创建表并加载数据查询验证使用lateral view查询…

JVM 面试速记

JVM结构图 类加载器 Bootstrap Class Loader 启动类加载器 C Extension Class Loader 扩展类加载器 java Application Class Loader 应用程序加载器 启动类加载器 只加载包名为java,javax,sun开头的类 扩展类加载器负责加载JAVA_HOME/lib/ext目录的下的类&#xff0c;开发…

R包WGCNA---转录组WGCNA共表达网络构建(基本概念)

R包WGCNA---转录组WGCNA共表达网络构建&#xff08;基本概念&#xff09;1. WGCNA简介2. WGCNA分析原理&#xff08;1&#xff09;R包WGCNA的主要功能&#xff08;2&#xff09;WGCNA的基本概念和工作流程&#xff08;3&#xff09;WGCNA分析的常见问题及注意事项1. WGCNA简介 …

嵌入式开发-STM32硬件I2C驱动OLED屏

嵌入式开发-STM32硬件I2C驱动OLED屏 I2C简介 I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。 主器件用于启动总线传送数据&#xff0c;并产生时钟以开放传送的器件&#xff0c;此时任何被寻址的器件均…

zlMediaKit 10 http相关

HttpRequestSplitter.h HttpRequestSplitter 结构 ssize_t _content_len 0;size_t _remain_data_size 0;toolkit::BufferLikeString _remain_data;input 上次还有剩余的数据&#xff0c;就把这次的数据和上次的数据接上。 分包&#xff1a; const char *ptr data;if(!_re…

大数据之Hive(二)

文章目录前言一、Hive数据库和表操作&#xff08;一&#xff09;数据库操作1. 创建数据库2. 删除数据库&#xff08;二&#xff09;数据表操作1. 内部表和外部表的操作1.1 内部表操作1.2 外部表操作2. 复杂类型操作2.1 Array类型2.2 map类型2.3 struct类型前言 #博学谷IT学习技…

【数据结构与算法】二叉排序树平衡二叉树哈夫曼树

&#x1f525; 本文由 程序喵正在路上 原创&#xff0c;CSDN首发&#xff01; &#x1f496; 系列专栏&#xff1a;数据结构与算法 &#x1f320; 首发时间&#xff1a;2022年11月7日 &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e;…

Oracle 处理json数据

文章目录备注:一. Json数据存储二. Json数据insert三. json数据update四. json数据查询五. 常用的json函数5.1 json_array5.2 JSON_ARRAYAGG5.3 JSON_DATAGUIDE5.4 JSON_MERGEPATCH5.5 JSON_OBJECT5.6 JSON_OBJECTAGG5.7 JSON_QUERY5.8 json_serialize5.9 JSON_TABLE5.10 JSON_…