【超详细!】Python微信公众号开发(2)

上次我们已经完成了微信公众号开发环境的搭建,并完成了服务器和微信公众号的校验。下面让我们来开始实际开发。

如果还没有微信公众号开发环境的,请参考我上一篇文章:

【超详细!超多图!】Python微信公众号开发(1)

本篇文章的内容为带领大家打通用户与服务器的信息交流通道:用户发的消息能在服务器收到,服务器能回复消息给用户。

0. 准备工作

0.1 代码修改

昨天的代码只是完成了微信公众号和服务器的校验,并没有地方处理用户的消息,下面我们来加上。

python 复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask, request
import hashlib

app = Flask(__name__)

##### 修改1:将昨天的校验代码封装成单独的函数 #####
def verify_wechat(request):
    # 设置token,开发者配置中心使用
    token = 'xxxxx'   # <------ 替换成你自定义的Token

    # 获取微信服务器发送过来的参数
    data = request.args
    signature = data.get('signature')
    timestamp = data.get('timestamp')
    nonce = data.get('nonce')
    echostr = data.get('echostr')

    # 对参数进行字典排序,拼接字符串
    temp = [timestamp, nonce, token]
    temp.sort()
    temp = ''.join(temp)

    # 加密
    if (hashlib.sha1(temp.encode('utf8')).hexdigest() == signature):
        return echostr
    else:
        return 'error', 403

##### 修改2:将服务访问路径由昨天的'/'换成'/wechatai' #####
#####       这里也可以不换路径,名字也可以你自己随意定 #####
@app.route('/wechatai', methods=['GET', 'POST'])
def wechatai():
	##### 修改3:当接受到的消息为GET请求时,执行校验,如果为POST请求,则认为是用户消息,处理用户消息
    if request.method == 'GET': 
        return verify_wechat(request)
    else:
        # 处理POST请求
        print("user request data: ", request.data)
        return "ok"  # <--------- 一定要加返回值!

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)

如果你执行了上面的"修改2",将访问路径改了,那需要到公众号里对服务器配置进行相应的修改,即在URL后面也加入这个路径,这样才能访问到。

0.2 启用服务器

  • 首先确保完成了上面的环境搭建和校验成功。
  • 确保你的程序已经开始运行

在配置服务器的公众号后台 ---> "服务器配置" ---> 点击"启用" ![在这里插入图片描述](img-blog.csdnimg.cn/direct/8eb3... =500x)

这样就相当于与咱们的服务器打通了,用户发的消息都会被微信服务器转发到咱们自己的服务上去,咱们就可以在自己的服务器上处理消息了。

1. 发个消息试试

首先你得关注这个公众号

1.1 发个消息试试

(1)打开这个公众号页面,发送消息"test" ![在这里插入图片描述](img-blog.csdnimg.cn/direct/ee7b... =300x) (2)去服务器上查看你的程序收到的消息 如果正常,你应该能在你的程序运行后台看到下面的信息。这一坨数据下文我会解释其意思,这里你先能收到它就OK了。

1.2 可能遇到的坑(我遇到的)

(1)服务器收不到用户消息:校验成功,但是用户发的消息服务器看不到。

  • 网上的解决方案:

微信公众号可以验证后台服务器(get),但却接收不到微信用户的消息及事件通知的一个可能性

  • 我的解决方案:以上解决方案并不能解决我的问题,我是在启用服务器的状态下,重新配置了一下服务器配置,然后就神奇的好了......

2. 用户消息处理

2.1 用户消息内容

下面我们来看下服务收到的用户消息内容:

python 复制代码
b'<xml><ToUserName><![CDATA[gh_fa8fa31]]></ToUserName>\n<FromUserName><![CDATA[oNexy6R4Ubm8gUCr1U]]></FromUserName>\n<CreateTime>1704420739</CreateTime>\n<MsgType><![CDATA[text]]></MsgType>\n<Content><![CDATA[test]]></Content>\n<MsgId>244014308074</MsgId>\n</xml>'

可以看到这是一个xml格式的字符串。用Python将以上xml字符串格式化打印出来,格式化打印xml字符串内容的代码如下:

python 复制代码
import xml.etree.ElementTree as ET   
def printXML(xml_content):
    # 创建XML元素
    element = ET.XML(xml_content)

    # 使用indent()函数进行格式化打印
    ET.indent(element)
    print(ET.tostring(element, encoding='unicode'))

调用函数打印:

python 复制代码
python printXML(request.data)

打印如下:

xml 复制代码
<xml>
  <ToUserName>gh_fa8fa31e</ToUserName>
  <FromUserName>oNexy6R49UkCr1U</FromUserName>
  <CreateTime>1704424380</CreateTime>
  <MsgType>text</MsgType>
  <Content>test</Content>
  <MsgId>244099103</MsgId>
</xml>

这是一个text类型的消息,内容是test。知道用户消息的内容结构之后,现在我们就可以提取出里面的Content来做一些相应的处理了,比如回复用户消息。

2.2 用户消息解析

先来提取用户消息中的Content内容,也就是用户发过来的文字:

(1)定义提取函数

python 复制代码
def getUserMessageContentFromXML(xml_content):
    # 解析XML字符串
    root = ET.fromstring(xml_content)

    # 提取数据
    content = root.find('Content').text
    from_user_name = root.find('FromUserName').text
    to_user_name = root.find('ToUserName').text
    return content, from_user_name, to_user_name

(2)调用提取函数

python 复制代码
@app.route('/wechatai', methods=['GET', 'POST'])
def wechatai():
    if request.method == 'GET':
        return verify_wechat(request)
    else:
        # 处理POST请求
        print("user request data: ", request.data)
        printXML(request.data)
        user_message_content, from_user_name, to_user_name = getUserMessageContentFromXML(request.data)  # <--------- 这里这里这里
        print("user message content: ", user_message_content)
        return "ok"

重新运行程序,用户发送过来消息后,应该能解析出结果如下:

3. 给用户回消息

上面我们能收到用户的消息,解析出用户发送的内容。但是如何给用户回消息呢?上面函数有一个 return "ok",但这只是给微信服务器回的消息,并不是给用户回的消息。

其实给用户回消息很简单,只需要将上面接收到的xml字符串,改一下里面的值即可。

(1)封装一个函数用来生成给回复的xml字符串

python 复制代码
def generate_response_xml(from_user_name, to_user_name, output_content):
    # 1. 先准备好回复的xml格式,后面只需要填充里面的字段即可
    output_xml = '''
    <xml>
        <ToUserName><![CDATA[%s]]></ToUserName>
        <FromUserName><![CDATA[%s]]></FromUserName>
        <CreateTime>%s</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[%s]]></Content>
    </xml>'''
    
    # 2. 通过 make_response 函数封装网络返回结构体
    response = make_response(output_xml % (from_user_name, to_user_name, str(int(time.time())), output_content))
    response.content_type = 'application/xml'
    return response

可以看到,xml的内容与接收到的基本一致,我们只需要填充里面的ToUserNameFromUserNameCreateTimeContent即可。

  • ToUserNameFromUserName:与接收到的xml保持一致
  • CreateTime:当前时间戳
  • Content:要回复给用户的内容

(2)调用函数生成回复内容的结构

python 复制代码
@app.route('/wechatai', methods=['GET', 'POST'])
def wechatai():
    if request.method == 'GET':
        return verify_wechat(request)
    else:
        # 处理POST请求
        print("user request data: ", request.data)
        printXML(request.data)
        user_message_content, from_user_name, to_user_name = getUserMessageContentFromXML(request.data)
        print("user message content: ", user_message_content)
        
        return generate_response_xml(from_user_name, to_user_name, "你好") # <------ 这一句代码!给用户回复一个"你好"

重新运行程序,用户发送过来消息后,在微信公众号用户对话界面,用户应该能收到"你好"的消息。 ![在这里插入图片描述](img-blog.csdnimg.cn/direct/0411... =300x)

至此,我们已经打通了用户与服务器的信息交流通道,后面就是在服务器端加自己的业务逻辑了。


从今天开始,持续学习,开始搞事情。踩坑不易,欢迎关注我 ,围观我! 有任何问题,欢迎+vx:jasper_8017,一起讨论,共同进步!

相关推荐
Moonbit7 分钟前
倒计时 2 天|Meetup 议题已公开,Copilot 月卡等你来拿!
前端·后端
天天摸鱼的java工程师1 小时前
解释 Spring 框架中 bean 的生命周期:一个八年 Java 开发的实战视角
java·后端
往事随风去1 小时前
那个让老板闭嘴、让性能翻倍的“黑科技”:基准测试最全指南
后端·测试
李广坤1 小时前
JAVA线程池详解
后端
调试人生的显微镜1 小时前
深入剖析 iOS 26 系统流畅度,多工具协同监控与性能优化实践
后端
蹦跑的蜗牛1 小时前
Spring Boot使用Redis实现消息队列
spring boot·redis·后端
非凡ghost1 小时前
HWiNFO(专业系统信息检测工具)
前端·javascript·后端
非凡ghost2 小时前
FireAlpaca(免费数字绘图软件)
前端·javascript·后端
非凡ghost2 小时前
Sucrose Wallpaper Engine(动态壁纸管理工具)
前端·javascript·后端
间彧2 小时前
从零到一搭建Spring Cloud Alibbaba项目
后端