Django+wechapy 微信公众号开发
博主好久没有更新了
这次整理下最近研究的简单的公众号平台搭建
这边用的是 wechatpy库 官网链接
1 # -*- coding: utf-8 -*- 2 # 公众号 3 # 作者: XX 4 # 时间: 2019-12-25 5 6 7 import logging 8 import requests 9 10 from Zmops import settings 11 from api.gaodei import GaoDeiBase 12 13 from wechat.pack import Pack 14 15 from django.http.response import HttpResponse, HttpResponseRedirect 16 from django.views.decorators.csrf import csrf_exempt 17 from django.shortcuts import redirect 18 from django.shortcuts import render 19 from django.contrib import messages 20 21 from wechatpy.exceptions import InvalidSignatureException, WeChatClientException 22 from wechatpy import parse_message 23 from wechatpy.replies import TextReply, ImageReply, VoiceReply 24 from wechatpy import WeChatClient 25 from wechatpy.oauth import WeChatOAuth 26 from wechatpy.utils import check_signature 27 28 29 logger = logging.getLogger("log") 30 31 32 def views_index(request): 33 return HttpResponse("Zmops 公众号平台") 34 35 36 def views_create_menu(request): 37 WechatBase().delete_menu() 38 WechatBase().create_menu() 39 return HttpResponse("成功创建自定义菜单") 40 41 42 class WechatServer(object): 43 """ 44 公众号服务类 45 """ 46 @csrf_exempt 47 def serve(self, request): 48 # GET 方式用于微信公众平台绑定验证 49 if request.method == "GET": 50 signature = request.GET.get("signature", "") 51 timestamp = request.GET.get("timestamp", "") 52 nonce = request.GET.get("nonce", "") 53 echo_str = request.GET.get("echostr", "") 54 try: 55 logger.info("Token:%s" % settings.Token) 56 logger.info("signature:%s" % signature) 57 logger.info("timestamp:%s" % timestamp) 58 logger.info("nonce:%s" % nonce) 59 check_signature(settings.Token, signature, timestamp, nonce) 60 except InvalidSignatureException: 61 echo_str = "错误的请求" 62 logger.info(echo_str) 63 response = HttpResponse(echo_str) 64 elif request.method == "POST": 65 66 msg = parse_message(request.body) 67 open_id = msg.source 68 msg_dict = msg.__dict__["_data"] 69 logger.info("用户open_id:%s" % open_id) 70 logger.info("用户msg_dict:%s" % msg_dict) 71 # 文本消息 72 if msg.type == "text": 73 reply = TextReply(message=msg) 74 reply.content = "收到你发送的文本消息" 75 xml = reply.render() 76 # 图片消息 77 elif msg.type == "image": 78 reply = ImageReply(message=msg) 79 reply.content = "收到你发送的图片消息" 80 reply.media_id = msg.media_id 81 xml = reply.render() 82 # 语音消息 83 elif msg.type == "voice": 84 reply = VoiceReply(message=msg) 85 reply.content = "收到你发送的语言消息" 86 reply.media_id = msg.media_id 87 xml = reply.render() 88 # 动作消息 89 elif msg.type == "event": 90 reply = TextReply(message=msg) 91 logger.info("操作的event:%s" % msg_dict["Event"]) 92 if msg_dict["Event"] == "subscribe": 93 reply.content = "你成功关注了此公众号\n我们的目标是\n让天下没有难做的运维 !\n" 94 xml = reply.render() 95 wx_user_info = WechatBase().get_wx_user_info(open_id) 96 Pack().user_create(_json=wx_user_info, subscribe=1) 97 98 elif msg_dict["Event"] == "unsubscribe": 99 reply.content = "你取消关注了此公众号" 100 xml = reply.render() 101 wx_user_info = WechatBase().get_wx_user_info(open_id) 102 Pack().user_create(_json=wx_user_info, subscribe=0) 103 104 elif msg_dict["Event"] == "LOCATION": 105 latitude = msg_dict["Latitude"] 106 longitude = msg_dict["Longitude"] 107 reply.content = { 108 "latitude": latitude, 109 "longitude": longitude 110 } 111 xml = reply.render() 112 else: 113 reply.content = "你的动作类型未知" 114 xml = reply.render() 115 # 未知消息类型 116 else: 117 # 捕捉公众号消息类型 118 logger.info("公众号接收到的消息类型:%s" % msg.type) 119 reply = TextReply(message=msg) 120 reply.content = "收到你发送的未知消息类型:%s" % msg.type 121 xml = reply.render() 122 response = HttpResponse(xml, content_type="application/xml") 123 else: 124 response = HttpResponse("公众号系统异常", content_type="application/xml") 125 return response 126 143 144 145 class WechatBase(object): 146 def __init__(self): 147 self.AppID = settings.AppID 148 self.AppSecret = settings.AppSecret 149 self.URL = settings.URL 150 151 def get_access_token(self): 152 response = requests.get(url="https://api.weixin.qq.com/cgi-bin/token", params={ 153 "grant_type": "client_credential", 154 "appid": self.AppID, 155 "secret": self.AppSecret 156 }) 157 text = response.text 158 159 if text["expires_in"] == 7200: 160 access_token = text["access_token"] 161 return access_token 162 else: 163 logger.info("获取access_token异常") 164 return False 165 166 # 获取微信代理授权 167 def get_wx_client(self): 168 logger.info("获取微信代理授权") 169 return WeChatClient(self.AppID, self.AppSecret) 170 171 def get_wx_user_info(self, openid): 172 wx_client = self.get_wx_client() 173 try: 174 wx_user_info = wx_client.user.get(user_id=openid) 175 logger.info("微信用户信息:%s" % wx_user_info) 176 return wx_user_info 177 except WeChatClientException as e: 178 logger.error(e) 179 return False 180 181 def get_wechat_oauth(self, redirect_url): 182 return WeChatOAuth(app_id=self.AppID, secret=self.AppSecret, redirect_uri=redirect_url, scope="snsapi_userinfo") 183 184 def create_menu(self): 185 wx_client = self.get_wx_client() 186 wx_client.menu.create({ 187 "button": [ 188 { 189 "type": "view", 190 "name": "更新菜单", 191 "url": self.URL + "/api/menu/create" 192 }, 193 { 194 "type": "view", 195 "name": "当前IP地图", 196 "url": self.URL + "/api/address_ip/get" 197 }, 198 { 199 "type": "view", 200 "name": "功能测试", 201 "url": self.URL + "/api/test" 202 } 203 ], 204 "matchrule": { 205 "tag_id": None, 206 "sex": None, 207 "country": "XX", 208 "province": "XX", 209 "city": "XX", 210 "client_platform_type": None 211 212 } 213 }) 214 logger.info("成功创建菜单") 215 216 def delete_menu(self): 217 wx_client = self.get_wx_client() 218 wx_client.menu.delete() 219 logger.info("成功删除菜单") 220 237 238 # 定义授权装饰器 239 def oauth(method): 240 def warpper(request): 241 if request.session.get("user_info", None) is None: 242 code = request.GET.get("code", None) 243 # logger.info()(request.get_raw_uri()) 244 wechat_oauth = WechatBase().get_wechat_oauth(request.get_raw_uri()) 245 url = wechat_oauth.authorize_url 246 if code: 247 try: 248 wechat_oauth.fetch_access_token(code) 249 user_info = wechat_oauth.get_user_info() 250 except Exception as e: 251 logger.error(e) 252 else: 253 request.session["user_info"] = user_info 254 else: 255 return redirect(url) 256 257 return method(request) 258 259 return warpper 260 261 262 @oauth 263 def views_get_user_info(request): 264 user_info = request.session.get("user_info") 265 logger.info(user_info) 266 return HttpResponse(str(user_info))
在上传代码部署过程中 会需要生成 requirements 文件
这边命令是
1 pip freeze > requirements.txt
基于已生成的 requirements文件 安装相关模块
1 pip install -r requirements.txt