1. 程式人生 > >python微信公眾號生成專屬二維碼--你再也不用去求人了

python微信公眾號生成專屬二維碼--你再也不用去求人了

需求:公司需要開發微信公眾號,並且和h5無縫對接。由於以前都是運營人員直接在微信公眾平臺進行編輯的,就從沒考慮如何做。前幾天運營人員有個需求,也就是我們平日在別人公眾號裡點選生成專屬二維碼,現在要求統計誰生成的二維碼,誰通過此二維碼進行的掃碼關注。

小公司,開發2人,原本想直接在網上找一個python的模組,import即可,想到今後要擴充套件功能會不會很麻煩。就自己幹了。(既然微信開發的api,如果很複雜的話,公眾號就不會這麼火了。)

思路:微信平臺就類似中介軟體, 我們的伺服器,以及使用者之間進行三角戀的變態關係。
1:和微信平臺建立信賴關係。就是配置咱們的伺服器和微信的連線。
2:微信事件推送,咱們伺服器收到後,進行反饋。(微信有5秒等待時間)
3:呼叫微信二維碼生成介面。(引數二維碼)
4:利用python qrcode生成引數二維碼,用PIL 將二維碼圖片和漂亮的背景圖片進行合併,paste到設計的指定位置。
4:將圖片上傳至微信素材
5:將訊息發給使用者。

整個流程沒有任何難點,難點就是特麼文件介面之間毫無聯絡,查起來效率老低了。不知為何市場上卻那麼多以此謀生的企業???(你只需要最多一天的時間基本搞定所有這些東西)
廢話不設了,
1:https://mp.weixin.qq.com/wiki 在文件中點選 接入指南。
token自己輸入一個你喜歡並且保密的字串。
當配置號url,token,EncodingAESKey 我們需要做的就是用我們的伺服器在此url連結下返回微信想要的資料。(目的告訴微信相信我哦),這一步通過後,才能進行下面的步驟。
所以按照文件要求:
1)將token、timestamp、nonce三個引數進行字典序排序
2)將三個引數字串拼接成一個字串進行sha1加密
3)開發者獲得加密後的字串可與signature對比,標識該請求來源於微信

ajaxLogger = logging.getLogger('ajax')
@csrf_exempt
def wechat_message_views(request):
    result = {}
    result["title"] = "微信訊息"
    if request.method == 'GET':
        if request.GET.has_key("signature"):
            signature = request.GET["signature"]
            timestamp = request.GET["timestamp"
] nonce = request.GET["nonce"] echostr = request.GET["echostr"] token = "你的touken" data_list = [token, timestamp, nonce] data_list.sort() weixin_sha1 = hashlib.sha1() weixin_sha1.update("".join(data_list)) weixin_sha1 = weixin_sha1.hexdigest() if weixin_sha1 == signature: response = HttpResponse(echostr) ajaxLogger.info("成功") else: response = HttpResponse("403") ajaxLogger.info("非法") else: ajaxLogger.info(request.get_host()) response = HttpResponse("ok") return response return what_you_want_do(request)

其中,@csrf_exempt很重要,不然就403了。

接入成功。

2:接收微信事件推送。
微信文件位置

(1)關注和取關事件推送
(2)掃描帶引數二維碼事件
就他兩個了,最簡單暴力的方法就是直接分析微信傳送的xml格式。根據xml內容進行函式執行。(這裡你可以用高階的python語法就執行)

在我們的伺服器url 介面函式那裡,我們的 what_you_want_do函式需要進行事件判讀,然後分發。你可以用策略模式等高階方法去完善。咱們直接if else…………(記得有仁熊說過,有的人寫了一輩子程式碼,永遠的if else)

from xml.dom.minidom import parseString
def weixin_deal_xml(nodes,key):
    try:
        node_data = nodes.getElementsByTagName(key)
        if node_data:
            return node_data[0].childNodes[0].data
        else:
            return []
    except Exception, e:
        ajaxLogger.error( "解析XML錯誤 : %s"%str(e) )
        return []

def what_you_want_do(request):
    #先要驗證request,方法和上面get一樣,咱也要知道request是否來自微信
    xml_result = request.body
    try:
        nodes = parseString(xml_result).documentElement
    except Exception, e:
        ajaxLogger.error("報錯啦,sb %s" %str(e))
        return HttpResponse("403")
    #研究發現微信的返回引數都有的,就這麼幹了,最好是封裝成函式,說不定今後有變化
    msg_type = weixin_deal_xml(nodes, "MsgType")
    user_open_id = weixin_deal_xml(nodes, "FromUserName")
    wechat_pub_id = weixin_deal_xml(nodes, "ToUserName")
    create_time = weixin_deal_xml(nodes, "CreateTime")

    if not msg_type:
        return HttpResponse("")
    if not user_open_id:
        return HttpResponse("")
    #此處開始處理 事件推送,根據事件推送型別,去處理
    if msg_type == "event":
        event = weixin_deal_xml(nodes, "Event")
        eventkey = weixin_deal_xml(nodes, "EventKey")
        return deal_wechat_event(event, eventkey, user_open_id, wechat_pub_id, create_time)
    else:
        pass

收到不同微信伺服器的事件推送,理論我們都應該就行xml的回覆。如果是
VIEW : 檢視跳轉,咱們可以不返回,有需要後臺儲存一下使用者的點選行為
CLICK :(這裡引數二維碼生成一定要是CLICK事件)。即在生成menu(https://api.weixin.qq.com/cgi-bin/menu/create?access_token={ACCESS_TOKEN})時,一定要將生成專屬二維碼設定成click。類似 {
“type”:”click”,
“name”:u”邀請好友”,
“key”:”V1001_你的_CODE_KEY”
}
此時,咱們做接收click事件,並通過key來判斷是哪一個,然後返回相應的函式。

由於咱們處理生成二維碼,還要進行和微信伺服器素材的互動行為,但事件推送等待時間有限。咱們採用非同步處理模式(gearman處理),先發一個訊息提示使用者,讓使用者等待一下,正在生成中。如:點選邀請好友按鈕

即what_you_want_do函式,不論收到來自微信的任何訊息,都應該返回一個xml訊息。這裡我們先返回一段話給使用者。
根據微信的訊息格式,這裡一定要注意,微信沒有在文件中進行說明,訊息必須回覆。真是坑爹,一定要回他哦。

import time
def response_to_wechat(touser, fromuser, text_content):
    data =  "<xml><ToUserName><![CDATA[%s]]></ToUserName>\
        <FromUserName><![CDATA[%s]]></FromUserName>\
        <CreateTime>%s</CreateTime>\
        <MsgType><![CDATA[%s]]></MsgType>\
        <Content><![CDATA[%s]]></Content>\
        </xml>"%(touser,
                fromuser,
                int(time.time()),
                "text",
                text_content
                )
    return HttpResponse(data, content_type="application/xml")

呼叫response_to_wechat 傳送一段等待的話給他,在這個之前呼叫非同步生成引數二維碼介面。

def deal_wechat_event(event, eventkey, user_open_id, wechat_pub_id, create_time):
    # 點選選單事件
    if event == "CLICK":
        if eventkey == "V1001_你的_CODE_KEY":
            params = {
                "user_open_id":user_open_id,
                "eventkey":eventkey,
                "wechat_pub_id":wechat_pub_id,
                "create_time":create_time
            }
            call_command('gearman_submit_job','worker_name', json.dumps(params),foreground=False)
            text_content = "協力正為您生成邀請二維碼,等待5秒左右即可收到。"
            return response_to_wechat(user_open_id, wechat_pub_id, text_content)

(上面的if ,else 都可以通過python技巧,以及設計模式進行更好的程式碼維護。自己進行吧。)

非同步的worker,我們在裡面定義處理函式。
函式一:生成引數二維碼,需求裡我們要儲存生成二維碼的使用者的資訊。(此使用者資訊即為引數key。當其他人通過掃描生成的二維碼時,我們要從推送的資訊中查詢微信返回的key是哪個使用者。)
文件這裡寫圖片描述

我們使用臨時二維碼,臨時素材。(因為永久的生成的個數太少了)

def create_scene_qrcode(user_open_id):
        scene_id = 100000000   #(每個使用者不一樣,你自己需要進行改變,如自增)
        # 獲取引數二維碼 url。自己進行二維碼圖片生成
        url = wechat_qr_imge_url(scene_id)
        image_data = create_wechat_qrcode(url)
        media_id = post_picture_to_weixin(image_data)
        create_time = int(time.time())
        send_user_message(user_open_id, media_id)
#帶引數二維碼
def wechat_qr_imge_url(final_scene_id):
    ACCESS_TOKEN = get_accesstoken()
    url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={ACCESS_TOKEN}".format(ACCESS_TOKEN=ACCESS_TOKEN)
    data = {
        "expire_seconds": 1000, 
        "action_name": "QR_SCENE", 
        "action_info": {"scene": 
            {"scene_id": final_scene_id}
            }
        }
    data = json.dumps(data)
    try:
        data_result = requests.post(url,data.encode('utf8'))
        result = data_result.json()
        ajaxLogger.info(str(result))
        if result.has_key("ticket"):
            ticket = result["ticket"]
            url = result["url"]
            return url
    except Exception, e:
        ajaxLogger.error("生成專屬引數二維碼 {error}".format(error=str(e)))

# 獲取二維碼ticket後,開發者可用ticket換取二維碼圖片,也可以將返回的url自行處理,咱們自此處理
#{"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
# 換取二維碼圖片
# https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET

get_accesstoken方法,實現了使用redis儲存token,因為token微信每天獲取次數有限制,並且有過期時間。所以咱們使用reids expire。將過期時間和 token過期一致即可。非常簡單

create_wechat_qrcode 生成合並圖片。
此函式目的就是1:生成二維碼,2:將二維碼和美麗的背景圖片進行合併。

from PIL import Image
import qrcode
from io import StringIO, BytesIO
def create_wechat_qrcode(params):
    #引數可自行調整
    qr = qrcode.QRCode(
        version=2,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=1
    )
    #二維碼填充內容
    qr.add_data(params)
    qr.make(fit=True)
    img = qr.make_image()
    img = img.convert("RGBA")
    #開啟背景圖片
    icon = Image.open("你的背景圖片地址.png")
    #根據設計將二維碼填充到制定位置
    icon.paste(img, ("位置座標", "位置座標"), img)
    buf = BytesIO()
    #生成二進位制檔案,直接發給微信
    icon.save(buf,format="PNG")
    file_content  = buf.getvalue()
    return file_content

此函式將圖片上傳至微信的臨時素材
post_picture_to_weixin

# 上傳圖訊息素材
def post_picture_to_weixin(rawimg):
    ACCESS_TOKEN = get_accesstoken()
    url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token={ACCESS_TOKEN}&type={TYPE}".format(ACCESS_TOKEN=ACCESS_TOKEN, TYPE="image")
    file_name = str(time.time()).split(".")[0] +  'tmp.png'
    #微信文件有檔案上傳時的要求
    files = { 'media' : (file_name, rawimg,'image/png')}
    res = requests.post(url, files=files)
    result_data = res.json()
    #media_id 通過media_id給微信使用者傳送圖片訊息
    if result_data.has_key("media_id"):
        media_id =  result_data["media_id"]
        return media_id

最後哦,send_user_message給使用者主動發訊息。(由於我們非同步處理,xml格式的回覆已經發給使用者,現在就得主動發訊息給使用者。)

def send_user_message(OPENID, MEDIA_ID, msgtype="image"):
    ACCESS_TOKEN = get_accesstoken()
    url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={ACCESS_TOKEN}".format(ACCESS_TOKEN=ACCESS_TOKEN)
    data = {
        "touser":OPENID,
        "msgtype":msgtype,
        "image":
        {
            "media_id":MEDIA_ID
        }
    }
    if msgtype == "text":
        data["text"] = {
            "content":"Hello World"
        }
    request_weixin(url, data)

def request_weixin(url, data):
    # 有些中文,以及json格式中的,必須使用ensure_ascii=False,不然有時會報錯
    data = json.dumps(data, ensure_ascii=False)
    try:
        data_result = requests.post(url,data.encode('utf8'))
        result = data_result.json()
        print result
        # ajaxLogger.info(str(result))
    except Exception, e:
        print e
        # ajaxLogger.error("設定客服失敗 {error}".format(error=str(e)))

這裡寫圖片描述
哈哈沒有美工,就拿logo放在中間啦,結果logo和二維碼,太醜陋了。

至此我們就完成了,生成專屬二維碼的整個流程和程式碼。
第一次在這裡發部落格,如果有錯誤歡迎大家指出來。如果幫助了大家,希望大家給個贊。

相關推薦

python公眾生成專屬--再也不用求人

需求:公司需要開發微信公眾號,並且和h5無縫對接。由於以前都是運營人員直接在微信公眾平臺進行編輯的,就從沒考慮如何做。前幾天運營人員有個需求,也就是我們平日在別人公眾號裡點選生成專屬二維碼,現在要求統計誰生成的二維碼,誰通過此二維碼進行的掃碼關注。 小公司,開

laravel生成公眾帶引數並響應掃描帶引數

微信公眾號後臺ip白名單、網頁介面域名之類的配置就不多說了,這裡主要配置的是開發->基本配置->伺服器配置(注:一旦啟用改配置,公眾號自動回覆就會失效): 1.伺服器地址(URL):這裡要

公眾獲取臨時

  我們做微信公眾號開發時為了推廣,可能需要服務端去生成公眾號的臨時二維碼,然後再進行一定的圖片合成操作,製作一張漂亮的推廣海報。別人掃一下二維碼進入關注公眾號介面,點選關注我們可以拿到二維碼裡面的資訊官網地址   記錄一下獲取臨時二維碼操作過程。   1.獲取

基於公眾掃描裝置並完成裝置啟用操作

微信公眾號掃描功能實現 自定義選單 配置微信公眾號資料互動伺服器 填寫伺服器配置 驗證訊息的確來自微信伺服器 獲取介面呼叫認證引數access_token 關閉自定義選單 建立自定義選單

公眾】建立ticket的2種方式

建立二維碼ticket的2種方式1. 場景二維碼分類•       目前有2種類型的二維碼:•       1、臨時二維碼,是有過期時間的,最長可以設定為在二維碼生成後的30天(即2592000秒)後過期,但能夠生成較多數量。臨時二維碼主要用於帳號繫結等不要求二維碼永久儲存的

公眾平臺 ---------java實現帶參生成本地圖片(2017/11/10更新版)

學藝不精,百度好多資料都沒弄成功,總是少一些包啊,方法啊,還有一些類啊 於是參考各種典籍自己寫了一下,發現並不難.分享一下,雖然只是簡單的實現了功能 ,可能存在bug,不足之處希望大家能指點一下 關於post get http協議工具類 HttpRequest.jav

通過數據流處理-小程序生成臨時

ant eat index ppi fun ppm nload his gif 1.小程序代碼 onLoad: function (options) { var that = this api.Login(function (login) {

公眾平臺中臨時的scene_id為32位非0整型

原文: 微信公眾平臺中臨時二維碼的scene_id為32位非0整型                                 &

asp源公眾生成帶參數的

exe public exec app UNC 電話 arr ssi ima Public Function Get_Openid() If Session("openid")="" Then s_SCOPE ="snsapi_base" Call

生成公眾帶引數加上使用者頭像(

 //微信兩維碼       $QR="./Uploads/Users/2015-09-07/14416192373.jpg";       $logo='http://7xk56y.com1.z0.glb.clouddn.com/FgkCSrkrr6VjMcK8v26DA

公眾平臺開發()息的分類.md

數據 msg 額外 環境 con pic 響應 我們 高質量 在上一篇博客中,我們只是簡單地與微信服務器建立了連接,接下來就是從微信服務器中接收信息了。在SecurityController中,我定義了兩個方法(get和post)。Get方法是我們用來與微信服務器建立連接,

Python 公眾發送消息

def app 是否 內容 msg mps action requests get 1. 公眾號測試地址 https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/in

公眾開發()--掃綁定賬號

stat 需要 ech 不同 指定 步驟 引導 connect amp 簡書地址:https://www.jianshu.com/p/b2884a226247 當業務系統產生消息需要通過微信推送給指定的用戶時,首頁需要將業務系統類的用戶和微信賬號建立一個關系。這裏采用的是微

C#公眾開發 -- ()驗證成為開發者

接下來就是驗證成為開發者了。先來看一下驗證的介面及需要填寫的資訊 在介面配置資訊中填寫需要處理驗證資訊的頁面或者一般性處理檔案,這裡以aspx頁面為例 URl中的格式為:http://XXX.com/wxapi.aspx ,其中XXX.com也即是上文提到的需要有一個外網可以訪問的域名,wxapi.a

公眾支付()H5調起支付

上一篇講到統一下單,得到微信返回的預支付交易會話標識prepay_id,那麼下單完成後要做的就是在html頁面調起支付視窗。 檢視官方文件:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&

公眾開發() -- 獲取使用者資訊 修改粉絲標籤

獲取code值 $appid=’’ // 微信支付申請對應的公眾號的APPID $urlCode=’’ // 處理code頁面 不能包含? 是微信可訪問頁面 $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid="

python 公眾開發 django 實現上傳圖片

廢話不多說,直接上碼,有問題請留言。該專案基於 python2.7 + django 1.11.3 url.py #coding:utf8 from django.conf.urls import url from app.views import * urlpatterns = [

Django公眾開發(公眾支付

前言   微信公眾號開發又一重要項就是微信支付,如何在微信公眾號中或者微信自帶的瀏覽器中實現微信支付呢?這就是本文的目的。   對於微信支付有幾種分類,一種是app支付(顧名思義給予一些軟體app使用的)、微信內H5支付(什麼意思呢,就是微信內建的瀏

公眾生成個性化選單

微信公眾號後來新增的介面,可以生成個性化選單,可以先看下個性化選單與自定義選單的資料格式有哪些不同。 在原有的資料格式基礎上,增加了以下部分: "matchrule":{ "group_id":"2", "sex":"1", "country":"中國",

掃描帶引數的關注公眾自動分組

今天學習了建立帶引數的二維碼並建立標籤,掃描帶引數的二維碼後自動分組到所在的標籤中。首先,先建立帶引數的二維碼,程式碼如下: public function qrcodeAdd(){ if(IS_GET){ $this->display('qrcode_a