Python開(kāi)發(fā)微信公眾平臺(tái)的方法詳解【基于weixin-knife】
本文實(shí)例講述了Python開(kāi)發(fā)微信公眾平臺(tái)的方法。分享給大家供大家參考,具體如下:
這兩天將之前基于微信公眾平臺(tái)的代碼重構(gòu)了下,基礎(chǔ)功能以庫(kù)的方式提供,提供了demo使用的是django,看著之前為趕進(jìn)度寫(xiě)的代碼真的慘不忍睹,所以weixin-knife產(chǎn)生了,正如其名,提供的是必要的功能,而不是完整的應(yīng)用。weixin-knife可以很方便的處理關(guān)注,取關(guān)注事件,處理文本消息,回復(fù)用戶(hù)信息,jssdk處理,oauth認(rèn)證,以及微信支付。
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"
上面處理了關(guān)注和取關(guān)事件,通過(guò)裝飾器處理的還算透明。
處理文本消息,回復(fù)圖文消息如下:
@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"], ["長(zhǎng)腿美女", "長(zhǎng)腿美女", "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, "推送消息測(cè)試") return "push ok" return "hello world"
如何文本是111或222,我們回復(fù)圖文消息,如何使push,我們使用客服接口推送消息,其它返回“hello world"
一般我們會(huì)使用oauth網(wǎng)頁(yè)授權(quán)獲取用戶(hù)的openid,如果是多個(gè)鏈接都需要通過(guò)oauth處理,代碼會(huì)很難看,通過(guò)裝飾器可以很好的處理這個(gè)問(wèn)題。
def sns_userinfo_callback(callback=None): """網(wǎng)頁(yè)授權(quán)獲取用戶(hù)信息裝飾器 callback(openid, userinfo): return user """ def wrap(func): @wraps(func) def inner(*args, **kwargs): request = args[0] #django第一個(gè)參數(shù)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()
在所有需要用戶(hù)openid的函數(shù)前使用sns_userinfo裝飾器就可以了,callback函數(shù)接收openid,userinfo,返回用戶(hù)實(shí)例,這樣就可以使用request.user獲取當(dāng)前用戶(hù)
@sns_userinfo def oauth(request): """網(wǎng)頁(yè)授權(quán)獲取用戶(hù)信息""" resp = HttpResponse(request.openid) resp.set_cookie("openid", Helper.sign_cookie(request.openid)) return resp
使用oauth需要保存cookie,不然每次用戶(hù)請(qǐng)求都需要授權(quán),需要走一遍完整的oauth流程,拖慢整體響應(yīng)。
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","充值測(cè)試") #商品描述 timeStamp = time.time() out_trade_no = "{0}{1}".format(WxPayConf_pub.APPID, int(timeStamp*100)) unifiedOrder.setParameter("out_trade_no", out_trade_no) #商戶(hù)訂單號(hào) unifiedOrder.setParameter("total_fee", str(money)) #總金額 unifiedOrder.setParameter("notify_url", WxPayConf_pub.NOTIFY_URL) #通知地址 unifiedOrder.setParameter("trade_type", "JSAPI") #交易類(lèi)型 unifiedOrder.setParameter("attach", "6666") #附件數(shù)據(jù),可分辨不同商家(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): """支付回調(diào)""" xml = request.raw_post_data #使用通用通知接口 notify = Notify_pub() notify.saveData(xml) print xml #驗(yàn)證簽名,并回應(yīng)微信。 #對(duì)后臺(tái)通知交互時(shí),如果微信收到商戶(hù)的應(yīng)答不是成功或超時(shí),微信認(rèn)為通知失敗, #微信會(huì)通過(guò)一定的策略(如30分鐘共8次)定期重新發(fā)起通知, #盡可能提高通知的成功率,但微信不保證通知最終能成功 if not notify.checkSign(): notify.setReturnParameter("return_code", FAIL) #返回狀態(tài)碼 notify.setReturnParameter("return_msg", "簽名失敗") #返回信息 else: result = notify.getData() if result["return_code"] == FAIL: notify.setReturnParameter("return_code", FAIL) notify.setReturnParameter("return_msg", "通信錯(cuò)誤") 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"] #商戶(hù)系統(tǒng)的訂單號(hào),與請(qǐng)求一致。 ###檢查訂單號(hào)是否已存在,以及業(yè)務(wù)代碼 return HttpResponse(notify.returnXml())
pay.html就是使用WeixinJSBridge.invode調(diào)用
$.post("/paydetail",{ money: $momey },function(data){ if(data){ var jsonobj = eval('('+data+')'); WeixinJSBridge.invoke('getBrandWCPayRequest', { "appId" : jsonobj.appId, //公眾號(hào)名稱(chēng),由商戶(hù)傳入 "timeStamp" : jsonobj.timeStamp, //時(shí)間戳 "nonceStr" : jsonobj.nonceStr, //隨機(jī)串 "package" : jsonobj.package,//擴(kuò)展包 "signType" : "MD5", //微信簽名方式:1.sha1 "paySign" : jsonobj.paySign //微信簽名 }); } } );
由于access_token, jsapi_ticket需要緩存,而緩存方式又依賴(lài)于具體環(huán)境,所以提供了一個(gè)Helper類(lèi),使用了django 的cache緩存。
class Helper(object): """微信具體邏輯幫組類(lèi)""" @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提供了類(lèi)級(jí)別的property,當(dāng)然實(shí)例也是可以用的。
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助力公眾平臺(tái)開(kāi)發(fā),你完全可以稍加修改用于flask等其它web框架。
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Python字符串操作技巧匯總》、《Python編碼操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》及《Python入門(mén)與進(jìn)階經(jīng)典教程》。
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
python里使用正則表達(dá)式的組嵌套實(shí)例詳解
這篇文章主要介紹了python里使用正則表達(dá)式的組嵌套實(shí)例詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下2017-10-10python神經(jīng)網(wǎng)絡(luò)使用tensorflow構(gòu)建長(zhǎng)短時(shí)記憶LSTM
這篇文章主要為大家介紹了python機(jī)器學(xué)習(xí)tensorflow構(gòu)建長(zhǎng)短時(shí)記憶網(wǎng)絡(luò)LSTM,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05python json.dumps() json.dump()的區(qū)別詳解
這篇文章主要介紹了python json.dumps() json.dump()的區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07淺談Python列表嵌套字典轉(zhuǎn)化的問(wèn)題
這篇文章主要介紹了淺談Python列表嵌套字典轉(zhuǎn)化的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04PyCharm創(chuàng)建Django項(xiàng)目的簡(jiǎn)單步驟記錄
PyCharm是一種Python?IDE,帶有一整套可以幫助用戶(hù)在使用Python語(yǔ)言開(kāi)發(fā)時(shí)提高其效率的工具,下面這篇文章主要給大家介紹了關(guān)于利用PyCharm創(chuàng)建Django項(xiàng)目的簡(jiǎn)單步驟,需要的朋友可以參考下2022-07-07sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程
這篇文章主要介紹了sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11Django獲取model中的字段名和字段的verbose_name方式
這篇文章主要介紹了Django獲取model中的字段名和字段的verbose_name方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-05-05python socket網(wǎng)絡(luò)編程步驟詳解(socket套接字使用)
這篇文章主要介紹了什么是套接字、PYTHON套接字模塊,提供一個(gè)簡(jiǎn)單的python socket編程,大家參考使用2013-12-12