微信SDK¶
提供微信登陆,公众号管理,微信支付,微信消息的全套功能
目录¶
快速开始¶
安装¶
使用pip
sudo pip install weixin-python
使用easy_install
sudo easy_install weixin-python
安装开发版本
sudo pip install git+https://github.com/zwczou/weixin-python@dev
功能¶
- 微信登陆
- 微信支付
- 微信公众号
- 微信消息
用法¶
异常¶
父异常类名为 WeixinError
子异常类名分别为 WeixinLoginError
WeixinPayError
WeixinMPError
WeixinMsgError
参数¶
WEIXIN_TOKEN
必填,微信主动推送消息的TOKENWEIXIN_SENDER
选填,微信发送消息的发送者WEIXIN_EXPIRES_IN
选填,微信推送消息的有效时间WEIXIN_MCH_ID
必填,微信商户ID,纯数字WEIXIN_MCH_KEY
必填,微信商户KEYWEIXIN_NOTIFY_URL
必填,微信回调地址WEIXIN_MCH_KEY_FILE
可选,如果需要用退款等需要证书的api,必选WEIXIN_MCH_CERT_FILE
可选WEIXIN_APP_ID
必填,微信公众号appidWEIXIN_APP_SECRET
必填,微信公众号appkey
上面参数的必填都是根据具体开启的功能有关,
如果你只需要微信登陆,就只要选择 WEIXIN_APP_ID
WEIXIN_APP_SECRET
- 微信消息
WEIXIN_TOKEN
WEIXIN_SENDER
WEIXIN_EXPIRES_IN
- 微信登陆
WEIXIN_APP_ID
WEIXIN_APP_SECRET
- 微信公众平台
WEIXIN_APP_ID
WEIXIN_APP_SECRET
- 微信支付
WEIXIN_APP_ID
WEIXIN_MCH_ID
WEIXIN_MCH_KEY
WEIXIN_NOTIFY_URL
WEIXIN_MCH_KEY_FILE
WEIXIN_MCH_CERT_FILE
初始化¶
如果使用flask
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from flask import Flask, jsonify, request, url_for
from weixin import Weixin, WeixinError
app = Flask(__name__)
app.debug = True
# 具体导入配
# 根据需求导入仅供参考
app.config.fromobject(dict(WEIXIN_APP_ID='', WEIXIN_APP_SECRET=''))
# 初始化微信
weixin = Weixin()
weixin.init_app(app)
# 或者
# weixin = Weixin(app)
如果不使用flask
# 根据需求导入仅供参考
config = dict(WEIXIN_APP_ID='', WEIXIN_APP_SECRET='')
weixin = Weixin(config)
微信消息¶
如果使用django,添加视图函数为
url(r'^/$', weixin.django_view_func(), name='index'),
如果为flask,添加视图函数为
app.add_url_rule("/", view_func=weixin.view_func)
@weixin.all
def all(**kwargs):
"""
监听所有没有更特殊的事件
"""
return weixin.reply(kwargs['sender'], sender=kwargs['receiver'], content='all')
@weixin.text()
def hello(**kwargs):
"""
监听所有文本消息
"""
return "hello too"
@weixin.text("help")
def world(**kwargs):
"""
监听help消息
"""
return dict(content="hello world!")
@weixin.subscribe
def subscribe(**kwargs):
"""
监听订阅消息
"""
print kwargs
return "欢迎订阅我们的公众号"
微信登陆¶
@app.route("/login")
def login():
"""登陆跳转地址"""
openid = request.cookies.get("openid")
next = request.args.get("next") or request.referrer or "/",
if openid:
return redirect(next)
callback = url_for("authorized", next=next, _external=True)
url = weixin.authorize(callback, "snsapi_base")
return redirect(url)
@app.route("/authorized")
def authorized():
"""登陆回调函数"""
code = request.args.get("code")
if not code:
return "ERR_INVALID_CODE", 400
next = request.args.get("next", "/")
data = weixin.access_token(code)
openid = data.openid
resp = redirect(next)
expires = datetime.now() + timedelta(days=1)
resp.set_cookie("openid", openid, expires=expires)
return resp
微信支付¶
注意: 微信网页支付的timestamp参数必须为字符串
@app.route("/pay/jsapi")
def pay_jsapi():
"""微信网页支付请求发起"""
try:
out_trade_no = weixin.nonce_str
raw = weixin.jsapi(openid="openid", body=u"测试", out_trade_no=out_trade_no, total_fee=1)
return jsonify(raw)
except WeixinError, e:
print e.message
return e.message, 400
@app.route("/pay/notify")
def pay_notify():
"""
微信异步通知
"""
data = weixin.to_dict(request.data)
if not weixin.check(data):
return weixin.reply("签名验证失败", False)
# 处理业务逻辑
return weixin.reply("OK", True)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=9900)
微信公众号¶
注意:
如果使用分布式,需要自己实现access_token
跟jsapi_ticket
函数
access_token
默认保存在~/.access_token
jsapi_ticket
默认保存在~/.jsapi_ticket
默认在(HOME)目录下面,如果需要更改到指定的目录,可以导入库之后修改,如下
import weixin
DEFAULT_DIR = "/tmp"
获取公众号唯一凭证
weixin.access_token
获取ticket
weixin.jsapi_ticket
创建临时qrcode
data = weixin.qrcode_create(123, 30)
print weixin.qrcode_show(data.ticket)
创建永久性qrcode
# scene_id类型
weixin.qrcode_create_limit(123)
# scene_str类型
weixin.qrcode_create_limit("456")
长链接变短链接
weixin.shorturl("http://example.com/test")
微信登陆¶
功能¶
- 支持snsapi_base, 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
- 支持snsapi_userinfo, 以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
文档¶
微信详细文档请点击
初始化¶
from weixin import WeixinLogin
# from weixin.login import WeixinLogin
login = WeixinLogin('app_id', 'app_key')
引导用户跳转到授权页面¶
url = login.authorize("http://code.show/login/weixin/callback", "snsapi_base")
通过code换取网页授权access_token¶
data = login.access_token(code)
print data.access_token
print data.refresh_token
print data.openid
小程序通过js_code换取session跟openid¶
data = login.jscode2session(code)
刷新token¶
login.refresh_token(data.refresh_token)
用法¶
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from flask import Flask, redirect, request, url_for
from weixin.login import WeixinLogin
app = Flask(__name__)
app_id = ''
app_secret = ''
wx_login = WeixinLogin(app_id, app_secret)
@app.route("/login")
def login():
openid = request.cookies.get("openid")
next = request.args.get("next") or request.referrer or "/",
if openid:
return redirect(next)
callback = url_for("authorized", next=next, _external=True)
url = wx_login.authorize(callback, "snsapi_base")
return redirect(url)
@app.route("/authorized")
def authorized():
code = request.args.get("code")
if not code:
return "ERR_INVALID_CODE", 400
next = request.args.get("next", "/")
data = wx_login.access_token(code)
openid = data.openid
resp = redirect(next)
expires = datetime.now() + timedelta(days=1)
resp.set_cookie("openid", openid, expires=expires)
return resp
微信支付¶
文档¶
微信详细文档请点击
初始化¶
from weixin.pay import WeixinPay, WeixinPayError
# 或者
# from weixin import WeixinPay, WeixinError
pay = WeixinPay('app_id', 'mch_id', 'mch_key', 'notify_url', '/path/to/key.pem', '/path/to/cert.pem') # 后两个参数可选
统一下单¶
注意:
默认spbill_create_ip
的值为request.remote_addr
,如果没有安装flask,请在参数后面带上spbill_create_ip
必填参数
- out_trade_no 商户订单号
- body 商品描述
- total_fee 商品费用(分)
- trade_type 交易类型
条件参数
- openid 如果
trade_type
为JSAPI
时必须 - product_id 如果
trade_type
为NATIVE
时必须
举例
try:
out_trade_no = wx_pay.nonce_str
raw = pay.unified_order(trade_type="JSAPI", openid="openid", body=u"测试", out_trade_no=out_trade_no, total_fee=1, attach="other info")
print raw
except WeixinError, e:
print e.message
网页端调起支付API¶
必填参数
- out_trade_no 商户订单号
- body 商品描述
- total_fee 商品费用(分)
- openid 用户标识
返回参数
- package 订单详情扩展字符串
- timeStamp 时间戳
- appId 公众号id
- nonceStr 随机字符串
- signType 清明方式
- sign 签名
try:
out_trade_no = wx_pay.nonce_str
raw = pay.jsapi(openid="openid", body=u"测试", out_trade_no=out_trade_no, total_fee=1, attach="other info")
print raw
except WeixinError, e:
print e
查询订单¶
参数,二选其一
- out_trade_no 商户订单号
- transaction_id 微信订单号
使用 out_trade_no
查询订单
print pay.order_query(out_trade_no=out_trade_no)
或者使用 transaction_id
查询
print pay.order_query(transaction_id='transaction_id')
申请退款¶
参数,二选其一,必选填写key,cert文件地址
- out_trade_no 商户订单号
- transaction_id 微信订单号
使用 out_trade_out
退款
print pay.refund(out_trade_no=out_trade_no)
或者使用 transaction_id
退款
print pay.refund(transaction_id='transaction_id')
退款查询¶
参数,4选一 * out_trade_no 商户订单号 * transaction_id 微信订单号 * out_refund_no 商户退款单号 * refund_id 微信退款单号
使用 out_trade_no
退款
print pay.refund_query(out_trade_no=out_trade_no)
工具函数¶
签名¶
sign = pay.sign(dict(a='b', b=2, c=3))
验证签名¶
pay.check(data(a='b', b=2, c=3, sign=sign))
回复消息¶
pay.reply("OK", True)
pay.reply("签名验证失败", False)
企业付款¶
必填参数
- openid 用户身份, amount 金额(分), partner_trade_no 商户订单号 desc企业付款备注
举例
raw = self.pay.pay_individual(openid=openid, amount=amount, partner_trade_no=partner_trade_no, desc=desc)
print raw
查询企业付款¶
必填参数
- partner_trade_no 商户订单号
举例
raw = self.pay.pay_individual_query(partner_trade_no=partner_trade_no)
print raw
用法¶
# -*- coding: utf-8 -*-
# from weixin import WeixinPay, WeixinError
from weixin.pay import WeixinPay, WeixinPayError
wx_pay = WeixinPay(app_id, mch_id, mch_key, notify_url)
@app.route("/pay/create")
def pay_create():
"""
微信JSAPI创建统一订单,并且生成参数给JS调用
"""
try:
out_trade_no = wx_pay.nonce_str
raw = wx_pay.jsapi(openid="openid", body=u"测试", out_trade_no=out_trade_no, total_fee=1)
return jsonify(raw)
except WeixinPayError, e:
# except WeixinError, e
print e.message
return e.message, 400
@app.route("/pay/notify", methods=["POST"])
def pay_notify():
"""
微信异步通知
"""
data = wx_pay.to_dict(request.data)
if not wx_pay.check(data):
return wx_pay.reply("签名验证失败", False)
# 处理业务逻辑
return wx_pay.reply("OK", True)
if __name__ == '__main__':
app.run()
微信消息¶
来源¶
本模块主要代码来源于lepture/flask-weixin
功能¶
- 接收微信推送消息
- 接受微信推送事件
- 发送微信消息
文档¶
微信详细文档请点击
初始化¶
from weixin import WeixinMsg
# from weixin.msg import WeixinMsg
msg = WeixinMsg('token')
# 如果使用flask
app.add_url_rule("/", view_func=msg.view_func)
# 如果使用django
# url(r'^/$', msg.django_view_func(), name='index')
接收消息¶
微信推送消息过来的时候,会先寻找最特殊的规则,然后再是普片的
监听所有¶
支持的消息类型¶
- 所有类型
@msg.all
- 文本类型
@msg.text()
@msg.text("help")
- 图片类型
@msg.image
- 视频类型
@msg.video
@msg.shortvideo
- 音频类型
@msg.voice
- 坐标类型
@msg.location
- 链接类型
@msg.link
- 事件类型
@msg.event
@msg.all
def all(**kwargs):
return "所有事件"
监听文本消息¶
@msg.text()
def text(**kwargs):
return "所有文本消息"
监听具体的文本消息¶
@msg.text("help")
def help(**kwargs):
return "可以通过4001000联系我们"
监听图片消息¶
@msg.image
def image():
return dict(content="image")
监听事件¶
支持的事件类型¶
- 订阅事件
@msg.subscribe
- 取消订阅事件
@msg.unsubscribe
- 点击事件
@msg.click
- 其它事件
@msg.{event}
监听订阅事件¶
@msg.subscribe
def subscribe():
return "欢迎关注我的公众号code_show"
监听取消订阅事件¶
@msg.unsubscribe
def unsubscribe():
return ""
监听点击事件¶
@msg.click
def click(**kwargs):
print kwargs
return ""
发送消息¶
支持回复消息的类型¶
- 文本消息
text
- 音乐消息
music
- 视频消息
video
- 音频消息
voice
- 图片消息
image
- 新闻消息
news
使用reply
函数¶
@msg.click
def click(**kwargs):
return msg.reply(kwargs['sender'], sender=kwargs['receiver'], content='click')
用法¶
# -*- coding: utf-8 -*-
from flask import Flask
from weixin.msg import WeixinMsg
app = Flask(__name__)
msg = WeixinMsg("e10adc3949ba59abbe56e057f20f883e", None, 0)
app.add_url_rule("/", view_func=msg.view_func)
@msg.all
def all_test(**kwargs):
print kwargs
# 或者直接返回
# return "all"
return msg.reply(
kwargs['sender'], sender=kwargs['receiver'], content='all'
)
@msg.text()
def hello(**kwargs):
return dict(content="hello too!", type="text")
@msg.text("world")
def world(**kwargs):
return msg.reply(
kwargs['sender'], sender=kwargs['receiver'], content='hello world!'
)
@msg.image
def image(**kwargs):
print kwargs
return ""
@msg.subscribe
def subscribe(**kwargs):
print kwargs
return ""
@msg.unsubscribe
def unsubscribe(**kwargs):
print kwargs
return ""
if __name__ == '__main__':
app.run(host="0.0.0.0", port=9900)
微信公众平台¶
文档¶
初始化¶
from weixin.mp import WeixinMP
mp = WeixinMP(app_id, app_secret)
获取公众号唯一凭证¶
print mp.access_token
获取jsticket¶
print mp.jsapi_ticket
jsapi签名,比如扫码或者分享¶
mp.jsapi_sign(url=request.url)
创建临时qrcode¶
data = mp.qrcode_create(123, 30)
print mp.qrcode_show(data.ticket)
创建永久性qrcode¶
# scene_id类型
mp.qrcode_create_limit(123)
# scene_str类型
mp.qrcode_create_limit("456")
长链接变短链接¶
mp.shorturl("http://example.com/test")
菜单管理¶
# 获取菜单
try:
print mp.menu_get()
except WeixinError:
pass
# 创建菜单
data = [
{
"type": "view",
"name": "测试",
"url": "http://code.show/",
},
]
print mp.menu_create(data)
# 删除菜单
print mp.menu_delete()
# 模板消息
print mp.get_all_private_template()
print mp.del_private_template("oHmefUCu3hUa1r23iun2gP3BM9MVn11g7Ob2J4VzpOg")
data = {
"first": {
"value":u"恭喜你购买成功!",
"color":"#173177"
},
"accountType":{
"value":u"巧克力",
"color":"#173177"
},
"account": {
"value":u"39.8元",
"color":"#173177"
},
"amount": {
"value":u"2014年9月22日",
"color":"#173177"
},
"result": {
"value":u"2014年9月22日",
"color":"#173177"
},
"remark":{
"value":u"欢迎再次购买\nabc\nefg",
"color":"#173177"
}
}
print mp.template_send("oHmefUCu3hUa1r23iun2gP3BM9MVn11g7Ob2J4VzpOg", "oYhHdsswUDolWKEbeybuA0sHr5W4", data)
更多用法参考 example/mp.py