这篇文章主要介绍了python使用微信sdk实现的微信支付功能,结合实例形式分析了python调用微信sdk接口实现微信支付功能的具体步骤与相关操作技巧,需要的朋友可以参考下
本文实例讲述了python使用微信sdk实现的微信支付功能。分享给大家供大家参考,具体如下:
最近一段时间一直在搞微信平台开发,v3.37版本微信支付接口变化贼大,所以就看着php的demo移植为python版,为了保持一致,所以接口方法基本都没有变,这样的好处就是不用写demo了,看着微信官方的demo照葫芦画瓢就可以了。
还可以点击此处本站下载。
我主要测试了jsapi调用方式,其它的调用方式并没有测试,如果你发现了bug,请多多pull request,我将不甚感激。
方便观看,代码贴于此。
#coding:utf-8
"""
created on 2014-11-24
@author: http://blog.csdn.net/yueguanghaidao
* 微信支付帮助库
* ====================================================
* 接口分三种类型:
* 【请求型接口】--wxpay_client_
* 统一支付接口类--unifiedorder
* 订单查询接口--orderquery
* 退款申请接口--refund
* 退款查询接口--refundquery
* 对账单接口--downloadbill
* 短链接转换接口--shorturl
* 【响应型接口】--wxpay_server_
* 通用通知接口--notify
* native支付——请求商家获取商品信息接口--nativecall
* 【其他】
* 静态链接二维码--nativelink
* jsapi支付--jsapi
* =====================================================
* 【commonutil】常用工具:
* trimstring(),设置参数时需要用到的字符处理函数
* createnoncestr(),产生随机字符串,不长于32位
* formatbizqueryparamap(),格式化参数,签名过程需要用到
* getsign(),生成签名
* arraytoxml(),array转xml
* xmltoarray(),xml转 array
* postxmlcurl(),以post方式提交xml到对应的接口url
* postxmlsslcurl(),使用证书,以post方式提交xml到对应的接口url
"""
import json
import time
import random
import urllib2
import hashlib
import threading
from urllib import quote
import xml.etree.elementtree as et
try:
import pycurl
from cstringio import stringio
except importerror:
pycurl = none
class wxpayconf_pub(object):
"""配置账号信息"""
#=======【基本信息设置】=====================================
#微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
appid = "wx8888888888888888"
#jsapi接口中获取openid,审核后在公众平台开启开发模式后可查看
appsecret = "48888888888888888888888888888887"
#受理商id,身份标识
mchid = "18888887"
#商户支付密钥key。审核通过后,在微信发送的邮件中查看
key = "48888888888888888888888888888886"
#=======【异步通知url设置】===================================
#异步通知url,商户根据实际开发过程设定
notify_url = "http://******.com/payback"
#=======【jsapi路径设置】===================================
#获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
js_api_call_url = "http://******.com/pay/?showwxpaytitle=1"
#=======【证书路径设置】=====================================
#证书路径,注意应该填写绝对路径
sslcert_path = "/******/cacert/apiclient_cert.pem"
sslkey_path = "/******/cacert/apiclient_key.pem"
#=======【curl超时设置】===================================
curl_timeout = 30
#=======【http客户端设置】===================================
http_client = "curl" # ("urllib", "curl")
class singleton(object):
"""单例模式"""
_instance_lock = threading.lock()
def new(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with cls._instance_lock:
if not hasattr(cls, "_instance"):
impl = cls.configure() if hasattr(cls, "configure") else cls
instance = super(singleton, cls).new(impl, *args, **kwargs)
instance.init(*args, **kwargs)
cls._instance = instance
return cls._instance
class urllibclient(object):
"""使用urlib2发送请求"""
def get(self, url, second=30):
return self.postxml(none, url, second)
def postxml(self, xml, url, second=30):
"""不使用证书"""
data = urllib2.urlopen(url, xml, timeout=second).read()
return data
def postxmlssl(self, xml, url, second=30):
"""使用证书"""
raise typeerror("please use curlclient")
class curlclient(object):
"""使用curl发送请求"""
def init(self):
self.curl = pycurl.curl()
self.curl.setopt(pycurl.ssl_verifyhost, false)
self.curl.setopt(pycurl.ssl_verifypeer, false)
#设置不输出header
self.curl.setopt(pycurl.header, false)
def get(self, url, second=30):
return self.postxmlssl(none, url, second=second, cert=false, post=false)
def postxml(self, xml, url, second=30):
"""不使用证书"""
return self.postxmlssl(xml, url, second=second, cert=false, post=true)
def postxmlssl(self, xml, url, second=30, cert=true, post=true):
"""使用证书"""
self.curl.setopt(pycurl.url, url)
self.curl.setopt(pycurl.timeout, second)
#设置证书
#使用证书:cert 与 key 分别属于两个.pem文件
#默认格式为pem,可以注释
if cert:
self.curl.setopt(pycurl.sslkeytype, "pem")
self.curl.setopt(pycurl.sslkey, wxpayconf_pub.sslkey_path)
self.curl.setopt(pycurl.sslcerttype, "pem")
self.curl.setopt(pycurl.sslcert, wxpayconf_pub.sslkey_path)
#post提交方式
if post:
self.curl.setopt(pycurl.post, true)
self.curl.setopt(pycurl.postfields, xml)
buff = stringio()
self.curl.setopt(pycurl.writefunction, buff.write)
self.curl.perform()
return buff.getvalue()
class httpclient(singleton):
@classmethod
def configure(cls):
if pycurl is not none and wxpayconf_pub.http_client != "urllib":
return curlclient
else:
return urllibclient
class common_util_pub(object):
"""所有接口的基类"""
def trimstring(self, value):
if value is not none and len(value) == 0:
value = none
return value
def createnoncestr(self, length = 32):
"""产生随机字符串,不长于32位"""
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
strs = []
for x in range(length):
strs.append(chars[random.randrange(0, len(chars))])
return "".join(strs)
def formatbizqueryparamap(self, paramap, urlencode):
"""格式化参数,签名过程需要使用"""
slist = sorted(paramap)
buff = []
for k in slist:
v = quote(paramap[k]) if urlencode else paramap[k]
buff.append("{0}={1}".format(k, v))
return "&".join(buff)
def getsign(self, obj):
"""生成签名"""
#签名步骤一:按字典序排序参数,formatbizqueryparamap已做
string = self.formatbizqueryparamap(obj, false)
#签名步骤二:在string后加入key
string = "{0}&key={1}".format(string,wxpayconf_pub.key)
#签名步骤三:md5加密
string = hashlib.md5(string).hexdigest()
#签名步骤四:所有字符转为大写
result_ = string.upper()
return result_
def arraytoxml(self, arr):
"""array转xml"""
xml = ["<xml>"]
for k, v in arr.iteritems():
if v.isdigit():
xml.append("<{0}>{1}</{0}>".format(k, v))
else:
xml.append("<{0}><![cdata[{1}]]></{0}>".format(k, v))
xml.append("</xml>")
return "".join(xml)
def xmltoarray(self, xml):
"""将xml转为array"""
array_data = {}
root = et.fromstring(xml)
for child in root:
value = child.text
array_data[child.tag] = value
return array_data
def postxmlcurl(self, xml, url, second=30):
"""以post方式提交xml到对应的接口url"""
return httpclient().postxml(xml, url, second=second)
def postxmlsslcurl(self, xml, url, second=30):
"""使用证书,以post方式提交xml到对应的接口url"""
return httpclient().postxmlssl(xml, url, second=second)
class jsapi_pub(common_util_pub):
"""jsapi支付——h5网页端调起支付接口"""
code = none #code码,用以获取openid
openid = none #用户的openid
parameters = none #jsapi参数,格式为json
prepay_id = none #使用统一支付接口得到的预支付id
curl_timeout = none #curl超时时间
def init(self, timeout=wxpayconf_pub.curl_timeout):
self.curl_timeout = timeout
def createoauthurlforcode(self, redirecturl):
"""生成可以获得code的url"""
urlobj = {}
urlobj["appid"] = wxpayconf_pub.appid
urlobj["redirect_uri"] = redirecturl
urlobj["response_type"] = "code"
urlobj["scope"] = "snsapi_base"
urlobj["state"] = "state#wechat_redirect"
bizstring = self.formatbizqueryparamap(urlobj, false)
return "https://open.weixin.qq.com/connect/oauth2/authorize?"+bizstring
def createoauthurlforopenid(self):
"""生成可以获得openid的url"""
urlobj = {}
urlobj["appid"] = wxpayconf_pub.appid
urlobj["secret"] = wxpayconf_pub.appsecret
urlobj["code"] = self.code
urlobj["grant_type"] = "authorization_code"
bizstring = self.formatbizqueryparamap(urlobj, false)
return "https://api.weixin.qq.com/sns/oauth2/access_token?"+bizstring
def getopenid(self):
"""通过curl向微信提交code,以获取openid"""
url = self.createoauthurlforopenid()
data = httpclient().get(url)
self.openid = json.loads(data)["openid"]
return self.openid
def setprepayid(self, prepayid):
"""设置prepay_id"""
self.prepay_id = prepayid
def setcode(self, code):
"""设置code"""
self.code = code
def getparameters(self):
"""设置jsapi的参数"""
jsapiobj = {}
jsapiobj["appid"] = wxpayconf_pub.appid
timestamp = int(time.time())
jsapiobj["timestamp"] = "{0}".format(timestamp)
jsapiobj["noncestr"] = self.createnoncestr()
jsapiobj["package"] = "prepay_id={0}".format(self.prepay_id)
jsapiobj["signtype"] = "md5"
jsapiobj["paysign"] = self.getsign(jsapiobj)
self.parameters = json.dumps(jsapiobj)
return self.parameters
class wxpay_client_pub(common_util_pub):
"""请求型接口的基类"""
response = none #微信返回的响应
url = none #接口链接
curl_timeout = none #curl超时时间
def init(self):
self.parameters = {} #请求参数,类型为关联数组
self.result = {} #返回参数,类型为关联数组
def setparameter(self, parameter, parametervalue):
"""设置请求参数"""
self.parameters[self.trimstring(parameter)] = self.trimstring(parametervalue)
def createxml(self):
"""设置标配的请求参数,生成签名,生成接口参数xml"""
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def postxml(self):
"""post请求xml"""
xml = self.createxml()
self.response = self.postxmlcurl(xml, self.url, self.curl_timeout)
return self.response
def postxmlssl(self):
"""使用证书post请求xml"""
xml = self.createxml()
self.response = self.postxmlsslcurl(xml, self.url, self.curl_timeout)
return self.response
def getresult(self):
"""获取结果,默认不使用证书"""
self.postxml()
self.result = self.xmltoarray(self.response)
return self.result
class unifiedorder_pub(wxpay_client_pub):
"""统一支付接口类"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
#设置curl超时时间
self.curl_timeout = timeout
super(unifiedorder_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
#检测必填参数
if any(self.parameters[key] is none for key in ("out_trade_no", "body", "total_fee", "notify_url", "trade_type")):
raise valueerror("missing parameter")
if self.parameters["trade_type"] == "jsapi" and self.parameters["openid"] is none:
raise valueerror("jsapi need openid parameters")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["spbill_create_ip"] = "127.0.0.1" #终端ip
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def getprepayid(self):
"""获取prepay_id"""
self.postxml()
self.result = self.xmltoarray(self.response)
prepay_id = self.result["prepay_id"]
return prepay_id
class orderquery_pub(wxpay_client_pub):
"""订单查询接口"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/pay/orderquery"
#设置curl超时时间
self.curl_timeout = timeout
super(orderquery_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
#检测必填参数
if any(self.parameters[key] is none for key in ("out_trade_no", "transaction_id")):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
class refund_pub(wxpay_client_pub):
"""退款申请接口"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/secapi/pay/refund"
#设置curl超时时间
self.curl_timeout = timeout
super(refund_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
if any(self.parameters[key] is none for key in ("out_trade_no", "out_refund_no", "total_fee", "refund_fee", "op_user_id")):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def getresult(self):
""" 获取结果,使用证书通信(需要双向证书)"""
self.postxmlssl()
self.result = self.xmltoarray(self.response)
return self.result
class refundquery_pub(wxpay_client_pub):
"""退款查询接口"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/pay/refundquery"
#设置curl超时时间
self.curl_timeout = timeout
super(refundquery_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
if any(self.parameters[key] is none for key in ("out_refund_no", "out_trade_no", "transaction_id", "refund_id")):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def getresult(self):
""" 获取结果,使用证书通信(需要双向证书)"""
self.postxmlssl()
self.result = self.xmltoarray(self.response)
return self.result
class downloadbill_pub(wxpay_client_pub):
"""对账单接口"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/pay/downloadbill"
#设置curl超时时间
self.curl_timeout = timeout
super(downloadbill_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
if any(self.parameters[key] is none for key in ("bill_date", )):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def getresult(self):
"""获取结果,默认不使用证书"""
self.postxml()
self.result = self.xmltoarray(self.response)
return self.result
class shorturl_pub(wxpay_client_pub):
"""短链接转换接口"""
def init(self, timeout=wxpayconf_pub.curl_timeout):
#设置接口链接
self.url = "https://api.mch.weixin.qq.com/tools/shorturl"
#设置curl超时时间
self.curl_timeout = timeout
super(shorturl_pub, self).init()
def createxml(self):
"""生成接口参数xml"""
if any(self.parameters[key] is none for key in ("long_url", )):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
return self.arraytoxml(self.parameters)
def getshorturl(self):
"""获取prepay_id"""
self.postxml()
prepay_id = self.result["short_url"]
return prepay_id
class wxpay_server_pub(common_util_pub):
"""响应型接口基类"""
success, fail = "success", "fail"
def init(self):
self.data = {} #接收到的数据,类型为关联数组
self.returnparameters = {} #返回参数,类型为关联数组
def savedata(self, xml):
"""将微信的请求xml转换成关联数组,以方便数据处理"""
self.data = self.xmltoarray(xml)
def checksign(self):
"""校验签名"""
tmpdata = dict(self.data) #make a copy to save sign
del tmpdata['sign']
sign = self.getsign(tmpdata) #本地签名
if self.data['sign'] == sign:
return true
return false
def getdata(self):
"""获取微信的请求数据"""
return self.data
def setreturnparameter(self, parameter, parametervalue):
"""设置返回微信的xml数据"""
self.returnparameters[self.trimstring(parameter)] = self.trimstring(parametervalue)
def createxml(self):
"""生成接口参数xml"""
return self.arraytoxml(self.returnparameters)
def returnxml(self):
"""将xml数据返回微信"""
returnxml = self.createxml()
return returnxml
class notify_pub(wxpay_server_pub):
"""通用通知接口"""
class nativecall_pub(wxpay_server_pub):
"""请求商家获取商品信息接口"""
def createxml(self):
"""生成接口参数xml"""
if self.returnparameters["return_code"] == self.success:
self.returnparameters["appid"] = wxpayconf_pub.appid #公众账号id
self.returnparameters["mch_id"] = wxpayconf_pub.mchid #商户号
self.returnparameters["nonce_str"] = self.createnoncestr() #随机字符串
self.returnparameters["sign"] = self.getsign(self.returnparameters) #签名
return self.arraytoxml(self.returnparameters)
def getproductid(self):
"""获取product_id"""
product_id = self.data["product_id"]
return product_id
class nativelink_pub(common_util_pub):
"""静态链接二维码"""
url = none #静态链接
def init(self):
self.parameters = {} #静态链接参数
def setparameter(self, parameter, parametervalue):
"""设置参数"""
self.parameters[self.trimstring(parameter)] = self.trimstring(parametervalue)
def createlink(self):
if any(self.parameters[key] is none for key in ("product_id", )):
raise valueerror("missing parameter")
self.parameters["appid"] = wxpayconf_pub.appid #公众账号id
self.parameters["mch_id"] = wxpayconf_pub.mchid #商户号
time_stamp = int(time.time())
self.parameters["time_stamp"] = "{0}".format(time_stamp) #时间戳
self.parameters["nonce_str"] = self.createnoncestr() #随机字符串
self.parameters["sign"] = self.getsign(self.parameters) #签名
bizstring = self.formatbizqueryparamap(self.parameters, false)
self.url = "weixin://wxpay/bizpayurl?"+bizstring
def geturl(self):
"""返回链接"""
self.createlink()
return self.url
def test():
c = httpclient()
assert c.get("http://www.baidu.com")[:15] == "<!doctype html>"
c2 = httpclient()
assert id(c) == id(c2)
if name == "main":
test()
以上就是python使用微信sdk实现的支付功能的详细内容。