微信公众号连接

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a10090492/article/details/80569250

首先第一步是验证,需要配置验证路由

在urls中

url(r'^wechat/',wechat)

然后在views视图中走验证的逻辑

然后这里有一个csrf_token问题。所以需要导入一个包

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

from .messages import Signature,Message
# 访问wechat不用携带csrf_token
@csrf_exempt
def wechat(request):
    # 走认证的的逻辑
    if request.method == 'GET':
        # 返回验证结果
        return HttpResponse(Signature.check_signature(request))

验证的详细逻辑在另一个新建的message.py文件中

class Signature(object):
    # 读取token值
    TOKEN = settings.WECHAT_TOKEN
    @classmethod
    def check_signature(cls,request):
        try:
            echostr = request.GET.get('echostr')
            nonce = request.GET.get('nonce')
            signature = request.GET.get('signature')
            timestamp = request.GET.get('timestamp')
            # 1.将token,timestamp,nonce 三个参数进行字典序排序
            tmpList = [cls.TOKEN, timestamp, nonce]
            tmpList.sort()
            # 2.将三个参数拼接成一个字符串
            tmpstr = ''.join(tmpList)
            # 3.对字符串进行哈希算法加密
            hashcode = hashlib.sha1(tmpstr.encode('utf-8')).hexdigest()
            # 4.验证加密后的字符串与signature是否相同,相同表示该请求源自于微信
            if hashcode == signature:
                # 返回随机字符串
                return echostr
    
        except Exception as e:
        
            return None

其中token的值在settings中设置的

而在视图中的另一个功能是接收用户传过来的数据,也就是post

    elif request.method == 'POST':
        
        msg = Message(request.body)
        result = msg.process_from_msgtype()
        return HttpResponse(result,content_type='xml/application')

同样在message中定义

 处理消息的类
class Message(object):
    '''<xml><ToUserName><![CDATA[{}]]></ToUserName><FromUserName><![CDATA[{}]]></FromUserName><CreateTime>{}</CreateTime><MsgType><![CDATA[voice]]></MsgType><Voice><MediaId><![CDATA[{}]]></MediaId></Voice></xml>'''
    def __init__(self,body):
        '''
        :param body: 微信服务器端发过来的数据 xml
        '''
        self.body = body
        self.MsgType = '' # 消息类型
        self.FromUserName = '' # 发送消息用户
        self.ToUserName = '' # 接收消息用户
        self.Content = '' # 接收文本信息内容
        self.CreateTime = '' # 消息推送时间
        self.MediaId = '' # 媒体文件id
        self.MsgId = '' # 消息id
        self.Event = '' # 事件类型
        self.xml_trans_attr()
    
    # 将xml数据转换为对象的属性值
    def xml_trans_attr(self):
        # 将字符串转换为节点树
        eleTree = ElementTree.fromstring(self.body)
        if eleTree.tag == 'xml':
            # for循环遍历节点树
            for child in eleTree:
                # 节点名称为key,节点数据为值,添加到字典中
                # 节点名称为属性名  节点数据为属性值  修改该对象属性
                setattr(self,child.tag,child.text)
    # 处理各类消息的函数
    def process_from_msgtype(self):
        result = ''
        # 判断消息类型
        if self.MsgType == 'text':
            # 文本消息
            result = self.text_msg()
        elif self.MsgType == 'image':
            # 处理图片消息
            result = self.image_msg()
        elif self.MsgType == 'voice':
            # 处理语音消息
            result = self.voice()
        elif self.MsgType == 'video':
            # 处理视频消息
            pass
        elif self.MsgType == 'event':
            # 处理事件消息
            if self.Event == 'subscribe':
                # 关注事件
                pass
            elif self.Event == 'unsubscribe':
                # 取消关注事件
                pass
            elif self.Event == 'CLICK':
                # 点击按钮事件
                # 判断点击的是哪个按钮
                if self.EventKey == '2-3':
                    self.Content = '郑州'
                    result = self.text_msg()
                
            elif self.Event == 'VIEW':
                # 跳转网页事件
                pass
        
        # 返回最终的处理结果
        return result
    
    # 处理文本事件
    def text_msg(self):
        # 取出文本消息内容
        if self.Content:
            # 根据Content 拼接天气预报地址
            url = 'http://api.map.baidu.com/telematics/v3/weather?location={}&output=json&ak=TueGDhCvwI6fOrQnLM0qmXxY9N0OkOiQ&callback=?'.format(self.Content)
            # 发送请求  拿回数据
            rs_dict = requests.get(url).json()
            # 判断城市名称是否正确
            if rs_dict['error'] != 0:
                # 不正确,返回错误的信息
                return TEXT_TEMPLATE.format(self.FromUserName,
                                            self.ToUserName,time.time(),'您输入的城市不存在,请检查后重试[玫瑰]')
            else:
                
                wea_dict = rs_dict['results'][0]
                # 城市
                city = wea_dict['currentCity']
                # pm值
                pm25 = float(wea_dict['pm25'])
                # 污染程度
                pollute = ''
                # 判断pm值的范围
                if 35>=pm25 >0:
                    pollute = '优[呲牙]'
                elif pm25 <= 75:
                    pollute = '良[白眼]'
                elif pm25 <= 115:
                    pollute = '轻度污染[晕]'
                elif pm25 <= 150:
                    pollute = '中度污染[难过]'
                elif pm25 <= 250:
                    pollute = '重度污染[吐]'
                else:
                    pollute = '严重污染[再见]'
                # 取出今天天气信息字典
                today = wea_dict['weather_data'][0]
                
                # 返回的文本信息
                content = ' [玫瑰][玫瑰][玫瑰]{}[玫瑰][玫瑰][玫瑰]\n pm值:{}\n 污染指数:{} \n 实时温度:{}\n 天气:{}\n 风级:{}\n 温度:{}\n'.format(city,pm25,pollute,today['date'],today['weather'],today['wind'],today['temperature'])
                # 拼接完整的回复内容
                return TEXT_TEMPLATE.format(self.FromUserName,
                                            self.ToUserName,time.time(),content)
    
    # 处理图片事件
    def image_msg(self):
        
        return IMAGE_TEMPLATE.format(self.FromUserName,self.ToUserName,
                                     time.time(),self.MediaId)
    # 处理语音事件
    def voice(self):
        return VOICE_TEMPLATE.format(self.FromUserName,self.ToUserName,
                                     time.time(),self.MediaId)

另外还有一个功能就是创建自定义菜单

views视图中的体现

@csrf_exempt
def wechat(request):
    # 走认证的的逻辑
    if request.method == 'GET':
        
        result = Signature.check_signature(request)
        
        if result:
            # 创建自定义菜单
            Menu.create_menu()
          
        
        # 返回验证结果
        return HttpResponse(result)
    elif request.method == 'POST':
        
        msg = Message(request.body)
        result = msg.process_from_msgtype()
        return HttpResponse(result,content_type='xml/application')

详细功能在在message文件中实现

因为创建自定义功能需要先获取access_token 所以先定义获取access_token的类

# 获取access_token
class Access_Token(object):
    # 拼接获取获取access_token的地址
    url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}'.format(settings.WECHAT_APPID,settings.WECHAT_SECRET)
    access_token = ''
    exprie_time = 0
    # 获取access_token值的函数
    @classmethod
    def get_access_token(cls):
        
        # 判断过期时间
        if cls.access_token and cls.exprie_time >= float(time.time()):
            return cls.access_token
        else:
            # 过期
            cls.get_access_token_form_url()
            return cls.access_token
    @classmethod
    def set_access_token(cls,access_token):
        cls.access_token = access_token
    
    # 请求拿到access_token
    @classmethod
    def get_access_token_form_url(cls):
        # 发起请求拿回数据
        response = requests.get(cls.url).json()
        # 判断请求结果中是否包含access_token
        if response.get('access_token',None):
            cls.set_access_token(response['access_token'])
            expires_in = response['expires_in']
            # 计算过期时间
            cls.exprie_time = float(time.time()) + float(expires_in)
        else:
            print(response)

然后再创建自定义类

class Menu(object):
    
    @classmethod
    def create_menu(cls):
        # 拼接url地址
        url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token={}'.format(Access_Token.get_access_token())
        data = {
            "button": [
                {
                    "name": "2",
                    "sub_button": [
                        {
                            "type": "view",
                            "name": "2-1",
                            "url": "http://www.soso.com/"
                        },
                        {
                            "type": "view",
                            "name": "2-2",
                            "url": "http://mp.weixin.qq.com",
                        
                        },
                        {
                            "type": "click",
                            "name": "2-3",
                            "key": "2-3"
                        }]
                },
                {
                    "name": "3",
                    "sub_button": [
                        {
                            "type": "scancode_push",
                            "name": "3-1",
                            "key": "3-1",
                            "sub_button": []
                        },
                        {
                            "type": "scancode_push",
                            "name": "3-2",
                            "key": "3-2",
                            "sub_button": []
                        },
                        {
                            "name": "3-3",
                            "type": "location_select",
                            "key": "3-3"
                        }
                    ]
                },
                {
                    "name": "4",
                    "sub_button": [
                        {
                            "type": "pic_sysphoto",
                            "name": "4-1",
                            "key": "4-1",
                            "sub_button": []
                        },
                        {
                            "type": "pic_photo_or_album",
                            "name": "4-2",
                            "key": "4-2",
                            "sub_button": []
                        },
                        {
                            "type": "pic_weixin",
                            "name": "4-3",
                            "key": "4-3",
                            "sub_button": []
                        }
                    ]
                }
            ]
        }
        
        response = requests.post(url,data=json.dumps(data))
        
        print(response.json())


展开阅读全文

没有更多推荐了,返回首页