Python开发微信公众平台的方法详解【基于weixin-knife】

本文实例讲述了Python开发微信公众平台的方法。分享给大家供大家参考,具体如下:

这两天将之前基于微信公众平台的代码重构了下,基础功能以库的方式提供,提供了demo使用的是django,看着之前为赶进度写的代码真的惨不忍睹,所以weixin-knife产生了,正如其名,提供的是必要的功能,而不是完整的应用。weixin-knife可以很方便的处理关注,取关注事件,处理文本消息,回复用户信息,jssdk处理,oauth认证,以及微信支付。

github地址:https://github.com/Skycrab/weixin-knife

首先看看怎么用

from .weixin import handler as HD
@HD.subscribe
def subscribe(xml):
  return "welcome to brain"
@HD.unsubscribe
def subscribe(xml):
  print "leave"
  return "leave brain"

上面处理了关注和取关事件,通过装饰器处理的还算透明。

处理文本消息,回复图文消息如下:

@HD.text
def text(xml):
  content = xml.Content
  if content == "111":
    return {"Title":"美女", "Description":"比基尼美女", "PicUrl":"http://9smv.com/static/mm/uploads/150411/2-150411115450247.jpg", "Url":"http://9smv.com/beauty/list?category=5"}
  elif content == "222":
    return [
      ["比基尼美女", "比基尼美女", "http://9smv.com/static/mm/uploads/150411/2-150411115450247.jpg", "http://9smv.com/beauty/list?category=5"],
      ["长腿美女", "长腿美女", "http://9smv.com/static/mm/uploads/150506/2-150506111A9648.jpg", "http://9smv.com/beauty/list?category=8"]
    ]
  elif content == "push":
    Helper.send_text_message(xml.FromUserName, "推送消息测试")
    return "push ok"
  return "hello world"

如何文本是111或222,我们回复图文消息,如何使push,我们使用客服接口推送消息,其它返回“hello world"

一般我们会使用oauth网页授权获取用户的openid,如果是多个链接都需要通过oauth处理,代码会很难看,通过装饰器可以很好的处理这个问题。

def sns_userinfo_callback(callback=None):
  """网页授权获取用户信息装饰器
  callback(openid, userinfo):
    return user
  """
  def wrap(func):
    @wraps(func)
    def inner(*args, **kwargs):
      request = args[0] #django第一个参数request
      openid = request.COOKIES.get('openid')
      userinfo = None
      if not openid:
        code = request.GET.get("code")
        if not code:
          current = "http://"+ request.get_host() + request.get_full_path()
          return redirect(WeixinHelper.oauth2(current))
        else:
          data = json.loads(WeixinHelper.getAccessTokenByCode(code))
          access_token, openid, refresh_token = data["access_token"], data["openid"], data["refresh_token"]
          #WeixinHelper.refreshAccessToken(refresh_token)
          userinfo = json.loads(WeixinHelper.getSnsapiUserInfo(access_token, openid))
      else:
        ok, openid = Helper.check_cookie(openid)
        if not ok:
          return redirect("/")
      request.openid = openid
      if callable(callback):
        request.user = callback(openid, userinfo)
      response = func(request)
      return response
    return inner
  return wrap
sns_userinfo = sns_userinfo_callback()

在所有需要用户openid的函数前使用sns_userinfo装饰器就可以了,callback函数接收openid,userinfo,返回用户实例,这样就可以使用request.user获取当前用户

@sns_userinfo
def oauth(request):
  """网页授权获取用户信息"""
  resp = HttpResponse(request.openid)
  resp.set_cookie("openid", Helper.sign_cookie(request.openid))
  return resp

使用oauth需要保存cookie,不然每次用户请求都需要授权,需要走一遍完整的oauth流程,拖慢整体响应。

weixin-knife提供了微信支付支持,稍微修改我之前移植的官方PHP版本,https://github.com/Skycrab/wzhifuSDK

@sns_userinfo
def pay(request):
  response = render_to_response("pay.html")
  response.set_cookie("openid", Helper.sign_cookie(request.openid))
  return response
@sns_userinfo
@catch
def paydetail(request):
  """获取支付信息"""
  openid = request.openid
  money = request.POST.get("money") or "0.01"
  money = int(float(money)*100)
  jsApi = JsApi_pub()
  unifiedOrder = UnifiedOrder_pub()
  unifiedOrder.setParameter("openid",openid) #商品描述
  unifiedOrder.setParameter("body","充值测试") #商品描述
  timeStamp = time.time()
  out_trade_no = "{0}{1}".format(WxPayConf_pub.APPID, int(timeStamp*100))
  unifiedOrder.setParameter("out_trade_no", out_trade_no) #商户订单号
  unifiedOrder.setParameter("total_fee", str(money)) #总金额
  unifiedOrder.setParameter("notify_url", WxPayConf_pub.NOTIFY_URL) #通知地址
  unifiedOrder.setParameter("trade_type", "JSAPI") #交易类型
  unifiedOrder.setParameter("attach", "6666") #附件数据,可分辨不同商家(string(127))
  try:
    prepay_id = unifiedOrder.getPrepayId()
    jsApi.setPrepayId(prepay_id)
    jsApiParameters = jsApi.getParameters()
  except Exception as e:
    print(e)
  else:
    print jsApiParameters
    return HttpResponse(jsApiParameters)
FAIL, SUCCESS = "FAIL", "SUCCESS"
@catch
def payback(request):
  """支付回调"""
  xml = request.raw_post_data
  #使用通用通知接口
  notify = Notify_pub()
  notify.saveData(xml)
  print xml
  #验证签名,并回应微信。
  #对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
  #微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
  #尽可能提高通知的成功率,但微信不保证通知最终能成功
  if not notify.checkSign():
    notify.setReturnParameter("return_code", FAIL) #返回状态码
    notify.setReturnParameter("return_msg", "签名失败") #返回信息
  else:
    result = notify.getData()
    if result["return_code"] == FAIL:
      notify.setReturnParameter("return_code", FAIL)
      notify.setReturnParameter("return_msg", "通信错误")
    elif result["result_code"] == FAIL:
      notify.setReturnParameter("return_code", FAIL)
      notify.setReturnParameter("return_msg", result["err_code_des"])
    else:
      notify.setReturnParameter("return_code", SUCCESS)
      out_trade_no = result["out_trade_no"] #商户系统的订单号,与请求一致。
      ###检查订单号是否已存在,以及业务代码
  return HttpResponse(notify.returnXml())

pay.html就是使用WeixinJSBridge.invode调用

$.post("/paydetail",{
  money: $momey
  },function(data){
   if(data){
    var jsonobj = eval('('+data+')');
    WeixinJSBridge.invoke('getBrandWCPayRequest', {
       "appId" : jsonobj.appId, //公众号名称,由商户传入
       "timeStamp" : jsonobj.timeStamp, //时间戳
       "nonceStr" : jsonobj.nonceStr, //随机串
       "package" : jsonobj.package,//扩展包
       "signType" : "MD5", //微信签名方式:1.sha1
       "paySign" : jsonobj.paySign //微信签名
       });
   }
  }
 );

由于access_token, jsapi_ticket需要缓存,而缓存方式又依赖于具体环境,所以提供了一个Helper类,使用了django 的cache缓存。

class Helper(object):
  """微信具体逻辑帮组类"""
  @class_property
  def access_token(cls):
    key = "ACCESS_TOKEN"
    token = cache.get(key)
    if not token:
      data = json.loads(WeixinHelper.getAccessToken())
      token, expire = data["access_token"], data["expires_in"]
      cache.set(key, token, expire-300)
    return token
  @class_property
  def jsapi_ticket(cls):
    key = "JSAPI_TICKET"
    ticket = cache.get(key)
    if not ticket:
      data = json.loads(WeixinHelper.getJsapiTicket(cls.access_token))
      ticket, expire = data["ticket"], data["expires_in"]
      cache.set(key, ticket, expire-300)
    return ticket

class_property提供了类级别的property,当然实例也是可以用的。

class class_property(object):
  """ A property can decorator class or instance
  class Foo(object):
    @class_property
    def foo(cls):
      return 42
  print(Foo.foo)
  print(Foo().foo)
  """
  def __init__(self, func, name=None, doc=None):
    self.__name__ = name or func.__name__
    self.__module__ = func.__module__
    self.__doc__ = doc or func.__doc__
    self.func = func
  def __get__(self, obj, type=None):
    value = self.func(type)
    return value

使用weixin-knife助力公众平台开发,你完全可以稍加修改用于flask等其它web框架。

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python字符串操作技巧汇总》、《Python编码操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》及《Python入门与进阶经典教程》。

希望本文所述对大家Python程序设计有所帮助。

(0)

相关推荐

  • python基于itchat实现微信群消息同步机器人

    最近 全栈数据工程师养成攻略 的微信群已经将近500人,开了二群之后为了打通不同微信群之间的消息,花了点时间做了个消息同步机器人,在任意群收到消息时同步到其他群,并且将聊天内容上传至数据库,以供进一步分析.统计和展示. 基本思路是,用 Python 模拟微信登陆,接收到群里消息后,对文本.图片.分享等各类消息类型分别处理,并转发至其他群. 前期准备 首先得有一个微信号,用于代码模拟登陆.由于我的微信号得自己留着用,现阶段注册微信又必须要手机号,于是只好特意办了个电信号,用来申请了一个新的微信,微

  • Python实现的微信公众号群发图片与文本消息功能实例详解

    本文实例讲述了Python实现的微信公众号群发图片与文本消息功能.分享给大家供大家参考,具体如下: 在微信公众号开发中,使用api都要附加access_token内容.因此,首先需要获取access_token.如下: #获取微信access_token def get_token(): payload_access_token={ 'grant_type':'client_credential', 'appid':'xxxxxxxxxxxxx', 'secret':'xxxxxxxxxxxxx

  • Python+微信接口实现运维报警

    说到运维报警,我觉得都可以写个长篇历史来详细解释了报警的前世来生,比如最早报警都是用邮件,但邮件实时性不高,比如下班回家总不能人一直盯着邮箱吧,所以邮件这种报警方式不适合用来报紧急的故障,日常磁盘利用率监控什么的可以用它来报没问题,网站宕机不能访问这种故障,用它就明显不合适了,那对这种业务稳定性要求比较高的业务,后来就发展成了用短信,就是公司买个短信机,提供一个http接口,然后运维人员写脚本把收集到的异常数据写入文件,然后脚本实时检测如果这个文件不为空,就调用短信机接口把文件里的内容发送出去,

  • 利用python微信库itchat实现微信自动回复功能

    前言 在论坛上看到了用Python登录微信并实现自动签到,才了解到一个新的Python库: itchat 利用Python 微信库itchat,可以实现自动回复等多种功能,好玩到根本停不下来啊,尤其是调戏调戏不懂计算机的,特别有成就感,哈哈!! 代码如下: #coding=utf8 import requests import itchat KEY = '8edce3ce905a4c1dbb965e6b35c3834d' def get_response(msg): apiUrl = 'http

  • Python编程之微信推送模板消息功能示例

    本文实例讲述了Python微信推送模板消息功能.分享给大家供大家参考,具体如下: 官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 具体代码如下: #!/usr/bin/env python #-*- coding: utf-8 -*- import httplib import json import MySQLdb #从数据库中获取access_token access_token="&quo

  • 基于python实现微信模板消息

    我的风格,废话不多说了,直接给大家贴代码了,并在一些难点上给大家附了注释,具体代码如下所示: #!/usr/bin/env python #-*- coding:utf-8 -*- import urllib2,json import datetime,time from config import * import sys reload(sys) sys.setdefaultencoding("utf-8") class WechatPush(): def __init__(self

  • Python开发之快速搭建自动回复微信公众号功能

    在之前的一篇文章 Python利用 AIML 和 Tornado 搭建聊天机器人微信订阅号 中用 aiml 实现了一个简单的英文聊天机器人订阅号.但是只能处理英文消息,现在用 图灵机器人 来实现一个中文的聊天机器人订阅号. 这里主要介绍如何利用 Python 的 Tornado Web框架以及wechat-python-sdk微信公众平台 Python 开发包来快速搭建微信公众号. 完整的公众号代码 GitHub 地址:green ,由于目前此公众号有一些功能正在开发中,此完整代码会与下文所描述

  • python实现给微信公众号发送消息的方法

    本文实例讲述了python实现给微信公众号发送消息的方法.分享给大家供大家参考,具体如下: 现在通过发微信公众号信息来做消息通知和告警已经很普遍了.最常见的就是运维通过zabbix调用shell脚本给微信发消息,起到告警的作用.当要发送的信息较多,而且希望按照指定格式显示的好看一点的时候,shell处理起来,个人感觉不太方便.于是我用Python重写了发微信的功能. #coding:utf-8 import urllib2 import json import sys def getMsg():

  • Python调用微信公众平台接口操作示例

    本文实例讲述了Python调用微信公众平台接口操作.分享给大家供大家参考,具体如下: 这里使用的是Django,其他类似 # coding=utf-8 from django.http import HttpResponse import hashlib, time, re from xml.etree import ElementTree as ET def weixin(request): token = "your token here" params = request.GET

  • Python编程实现微信企业号文本消息推送功能示例

    本文实例讲述了Python微信企业号文本消息推送功能.分享给大家供大家参考,具体如下: 企业号的创建.企业号应用的创建.组.tag.part就不赘述了,一搜一大堆,但是网上拿的那些个脚本好多都不好使,所以自己修了一个 坦率的讲,这个脚本是用来作为zabbix的通知媒介脚本的,本人是个菜鸟,如果哪里不对,大神们不要笑话,python也处于学习阶段,如果有哪些地方不合理,很希望可以不吝赐教,废话不多说,脚本奉上: #!/usr/bin/python # _*_coding:utf-8 _*_ imp

随机推荐