Python/Django 微信接口
注册或登陆 微信公众平台 点击左侧的 开发者中心
填写相应的网址,Token(令牌) 是随便写的,你自己想写什么就写什么,微信验证时检验是否写的和服务器上的TOKEN一样,一样则通过。
关注一下自强学堂的微信号吧,可以随时随地查阅教程哦,体验一下自强学堂的微信的各种功能再阅读效果更佳!
自己动手写微信的验证: views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #coding=utf-8 import hashlib import json from lxml import etree from django.utils.encoding import smart_str from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse from auto_reply.views import auto_reply_main # 修改这里 WEIXIN_TOKEN = 'write-a-value' @csrf_exempt def weixin_main(request): """ 所有的消息都会先进入这个函数进行处理,函数包含两个功能, 微信接入验证是GET方法, 微信正常的收发消息是用POST方法。 """ if request.method = = "GET" : signature = request.GET.get( "signature" , None ) timestamp = request.GET.get( "timestamp" , None ) nonce = request.GET.get( "nonce" , None ) echostr = request.GET.get( "echostr" , None ) token = WEIXIN_TOKEN tmp_list = [token, timestamp, nonce] tmp_list.sort() tmp_str = "%s%s%s" % tuple (tmp_list) tmp_str = hashlib.sha1(tmp_str).hexdigest() if tmp_str = = signature: return HttpResponse(echostr) else : return HttpResponse( "weixin index" ) else : xml_str = smart_str(request.body) request_xml = etree.fromstring(xml_str) response_xml = auto_reply_main(request_xml) # 修改这里 return HttpResponse(response_xml) |
使用第三方包实现:
关于Django开发微信,有已经做好的现在的包可以使用 wechat_sdk 这个包,使用文档 也比较完善,但是在处理加密一部分没有做,在微信公众平台上,需要用明文验证,如果要加密,自己参照微信官网的加密算法。
使用 wechat_sdk 的例子(自强学堂微信号简化后的例子):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.http.response import HttpResponse, HttpResponseBadRequest from django.views.decorators.csrf import csrf_exempt from wechat_sdk import WechatBasic from wechat_sdk.exceptions import ParseError from wechat_sdk.messages import TextMessage WECHAT_TOKEN = 'zqxt' AppID = '' AppSecret = '' # 实例化 WechatBasic wechat_instance = WechatBasic( token = WECHAT_TOKEN, appid = AppID, appsecret = AppSecret ) @csrf_exempt def index(request): if request.method = = 'GET' : # 检验合法性 # 从 request 中提取基本信息 (signature, timestamp, nonce, xml) signature = request.GET.get( 'signature' ) timestamp = request.GET.get( 'timestamp' ) nonce = request.GET.get( 'nonce' ) if not wechat_instance.check_signature( signature = signature, timestamp = timestamp, nonce = nonce): return HttpResponseBadRequest( 'Verify Failed' ) return HttpResponse( request.GET.get( 'echostr' , ''), content_type = "text/plain" ) # 解析本次请求的 XML 数据 try : wechat_instance.parse_data(data = request.body) except ParseError: return HttpResponseBadRequest( 'Invalid XML Data' ) # 获取解析好的微信请求信息 message = wechat_instance.get_message() # 关注事件以及不匹配时的默认回复 response = wechat_instance.response_text( content = ( '感谢您的关注!\n回复【功能】两个字查看支持的功能,还可以回复任意内容开始聊天' '\n【<a href="https://code.tuweizhong.com">自强学堂手机版</a>】' )) if isinstance (message, TextMessage): # 当前会话内容 content = message.content.strip() if content = = '功能' : reply_text = ( '目前支持的功能:\n1. 关键词后面加上【教程】两个字可以搜索教程,' '比如回复 "Django 后台教程"\n' '2. 回复任意词语,查天气,陪聊天,讲故事,无所不能!\n' '还有更多功能正在开发中哦 ^_^\n' '【<a href="https://code.tuweizhong.com">自强学堂手机版</a>】' ) elif content.endswith( '教程' ): reply_text = '您要找的教程如下:' response = wechat_instance.response_text(content = reply_text) return HttpResponse(response, content_type = "application/xml" ) |
下面是一个更详细复杂的使用例子:
models.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models class KeyWord(models.Model): keyword = models.CharField( '关键词' , max_length = 256 , primary_key = True , help_text = '用户发出的关键词' ) content = models.TextField( '内容' , null = True , blank = True , help_text = '回复给用户的内容' ) pub_date = models.DateTimeField( '发表时间' , auto_now_add = True ) update_time = models.DateTimeField( '更新时间' , auto_now = True , null = True ) published = models.BooleanField( '发布状态' , default = True ) def __unicode__( self ): return self .keyword class Meta: verbose_name = '关键词' verbose_name_plural = verbose_name |
views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.http.response import HttpResponse, HttpResponseBadRequest from django.views.decorators.csrf import csrf_exempt from wechat_sdk import WechatBasic from wechat_sdk.exceptions import ParseError from wechat_sdk.messages import (TextMessage, VoiceMessage, ImageMessage, VideoMessage, LinkMessage, LocationMessage, EventMessage ) from wechat_sdk.context.framework.django import DatabaseContextStore from .models import KeyWord as KeyWordModel # 实例化 WechatBasic wechat_instance = WechatBasic( token = 'zqxt' , appid = 'xx' , appsecret = 'xx' ) @csrf_exempt def index(request): if request.method = = 'GET' : # 检验合法性 # 从 request 中提取基本信息 (signature, timestamp, nonce, xml) signature = request.GET.get( 'signature' ) timestamp = request.GET.get( 'timestamp' ) nonce = request.GET.get( 'nonce' ) if not wechat_instance.check_signature( signature = signature, timestamp = timestamp, nonce = nonce): return HttpResponseBadRequest( 'Verify Failed' ) return HttpResponse( request.GET.get( 'echostr' , ''), content_type = "text/plain" ) # POST # 解析本次请求的 XML 数据 try : wechat_instance.parse_data(data = request.body) except ParseError: return HttpResponseBadRequest( 'Invalid XML Data' ) # 获取解析好的微信请求信息 message = wechat_instance.get_message() # 利用本次请求中的用户OpenID来初始化上下文对话 context = DatabaseContextStore(openid = message.source) response = None if isinstance (message, TextMessage): step = context.get( 'step' , 1 ) # 当前对话次数,如果没有则返回 1 # last_text = context.get('last_text') # 上次对话内容 content = message.content.strip() # 当前会话内容 if message.content = = '新闻' : response = wechat_instance.response_news([ { 'title' : '自强学堂' , 'picurl' : '/static/images/newlogo.png' , 'description' : '自强学堂致力于提供优质的IT技术教程, 网页制作,服务器后台编写,以及编程语言,如HTML,JS,Bootstrap,Python,Django。同时也提供大量在线实例,通过实例,学习更容易,更轻松。' , 'url' : 'https://code.tuweizhong.com' , }, { 'title' : '百度' , 'picurl' : 'http://doraemonext.oss-cn-hangzhou.aliyuncs.com/test/wechat-test.jpg' , 'url' : 'http://www.baidu.com' , }, { 'title' : 'Django 教程' , 'picurl' : '/media/uploads/images/django_logo_20140508_061519_35.jpg' , 'url' : 'https://code.tuweizhong.com/django/django-tutorial.html' , } ]) return HttpResponse(response, content_type = "application/xml" ) else : try : keyword_object = KeyWordModel.objects.get(keyword = content) reply_text = keyword_object.content except KeyWordModel.DoesNotExist: try : reply_text = KeyWordModel.objects.get(keyword = '提示' ).content except KeyWordModel.DoesNotExist: reply_text = ( '/:P-(好委屈,数据库翻个遍也没找到你输的关键词!\n' '试试下面这些关键词吧:\nKEYWORD_LIST\n' '<a href="http://www.rxnfinder.org">RxnFinder</a>' '感谢您的支持!/:rose' ) # 将新的数据存入上下文对话中 context[ 'step' ] = step + 1 context[ 'last_text' ] = content context.save() # 非常重要!请勿忘记!临时数据保存入数据库! if 'KEYWORD_LIST' in reply_text: keyword_objects = KeyWordModel.objects.exclude(keyword__in = [ '关注事件' , '测试' , 'test' , '提示' ]). filter (published = True ) keywords = ( '{}. {}' . format ( str (i), k.keyword) for i, k in enumerate (keyword_objects, 1 )) reply_text = reply_text.replace( 'KEYWORD_LIST' , '\n' .join(keywords)) # 文本消息结束 elif isinstance (message, VoiceMessage): reply_text = '语音信息我听不懂/:P-(/:P-(/:P-(' elif isinstance (message, ImageMessage): reply_text = '图片信息我也看不懂/:P-(/:P-(/:P-(' elif isinstance (message, VideoMessage): reply_text = '视频我不会看/:P-(' elif isinstance (message, LinkMessage): reply_text = '链接信息' elif isinstance (message, LocationMessage): reply_text = '地理位置信息' elif isinstance (message, EventMessage): # 事件信息 if message. type = = 'subscribe' : # 关注事件(包括普通关注事件和扫描二维码造成的关注事件) follow_event = KeyWordModel.objects.get(keyword = '关注事件' ) reply_text = follow_event.content # 如果 key 和 ticket 均不为空,则是扫描二维码造成的关注事件 if message.key and message.ticket: reply_text + = '\n来源:扫描二维码关注' else : reply_text + = '\n来源:搜索名称关注' elif message. type = = 'unsubscribe' : reply_text = '取消关注事件' elif message. type = = 'scan' : reply_text = '已关注用户扫描二维码!' elif message. type = = 'location' : reply_text = '上报地理位置' elif message. type = = 'click' : reply_text = '自定义菜单点击' elif message. type = = 'view' : reply_text = '自定义菜单跳转链接' elif message. type = = 'templatesendjobfinish' : reply_text = '模板消息' response = wechat_instance.response_text(content = reply_text) return HttpResponse(response, content_type = "application/xml" ) |