宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動態(tài)
精選推薦

微信公眾號入門基礎(chǔ)知識指引

管理 管理 編輯 刪除

1開啟公眾號開發(fā)者模式

公眾平臺技術(shù)文檔的目的是為了簡明扼要的說明接口的使用,語句難免苦澀難懂,甚至對于不同的讀者,有語意歧義。萬事皆是入門難,對于剛?cè)腴T的開發(fā)者講,更是難上加難。

為了降低門檻,彌補不足,我們編寫了《開發(fā)者指引》來講解微信開放平臺的基礎(chǔ)常見功能,旨在幫助大家入門微信開放平臺的開發(fā)者模式。

已熟知接口使用或有一定公眾平臺開發(fā)經(jīng)驗的開發(fā)者,請直接跳過本文。這篇文章不會給你帶來厲害的編碼技巧亦或接口的深層次講解。對于現(xiàn)有接口存在的疑問,可訪問 #公眾號社區(qū) 發(fā)帖交流、聯(lián)系騰訊客服或使用微信反饋。

1.1 申請服務(wù)器

以騰訊云服務(wù)器為示例:騰訊云服務(wù)器購買入口

如你已有小程序,并且已開通小程序云開發(fā),則可以使用 公眾號環(huán)境共享 能力,在公眾號中使用云開發(fā)。

1.2 搭建服務(wù)

以web.py網(wǎng)絡(luò)框,python,騰訊云服務(wù)器為例介紹。

1)安裝/更新需要用到的軟件

安裝python2.7版本以上

安裝web.py

安裝libxml2, libxslt, lxml python

2)編輯代碼,如果不懂python 語法,請到python官方文檔查詢說明。

vim main.py

# -*- coding: utf-8 -*-
# filename: main.py
import web

urls = (
    '/wx', 'Handle',
)

class Handle(object):
    def GET(self):
        return "hello, this is handle view"

if __name__ == '__main__':
    app = web.application(urls, globals())
    app.run()

3)如果出現(xiàn)“socket.error: No socket could be created“錯誤信息,可能為80端口號被占用,可能是沒有權(quán)限,請自行查詢解決辦法。如果遇見其他錯誤信息,請到web.py官方文檔,學(xué)習(xí)webpy 框架3執(zhí)行命令:sudo python main.py 80 。

4)url填寫:http://外網(wǎng)IP/wx (外網(wǎng)IP請到騰訊云購買成功處查詢)。如下圖,一個簡單的web應(yīng)用已搭建。

a345220230717112538941.png

1.3 申請公眾號

申請公眾號網(wǎng)頁

0c7c7202307171125483689.png

郵箱激活后,選擇公眾號類型。不同的公眾號擁有不同的能力,詳情請見wiki:公眾號接口權(quán)限說明,當然,服務(wù)號、企業(yè)號需要一定的證件和相關(guān)資料填寫,如果證件一時不能準備好,沒關(guān)系,公眾號其實已注冊,下次可以根據(jù)此郵箱&密碼登錄再選擇。

c4bb8202307171125578668.png

1.4 開發(fā)者基本配置

1) 公眾平臺官網(wǎng)登錄之后,找到“基本配置”菜單欄

8b7ee202307171126097720.png

4e06c202307171126149365.png

2) 填寫配置 url填寫:http://外網(wǎng)IP/wx 。外網(wǎng)IP請到騰訊云購買成功處查詢。 http的端口號固定使用80,不可填寫其他。 Token:自主設(shè)置,這個token與公眾平臺wiki中常提的access_token不是一回事。這個token只用于驗證開發(fā)者服務(wù)器。

c151620230717112625173.png

3) 現(xiàn)在選擇提交肯定是驗證token失敗,因為還需要完成代碼邏輯。改動原先main.py文件,新增handle.py

a)vim main.py

# -*- coding: utf-8 -*-
# filename: main.py
import web
from handle import Handle

urls = (
    '/wx', 'Handle',
)

if __name__ == '__main__':
    app = web.application(urls, globals())
    app.run()

b)vim handle.py

先附加邏輯流程圖

21c30202307171126428399.png

# -*- coding: utf-8 -*-
# filename: handle.py

import hashlib
import web

class Handle(object):
    def GET(self):
        try:
            data = web.input()
            if len(data) == 0:
                return "hello, this is handle view"
            signature = data.signature
            timestamp = data.timestamp
            nonce = data.nonce
            echostr = data.echostr
            token = "xxxx" #請按照公眾平臺官網(wǎng)\基本配置中信息填寫

            list = [token, timestamp, nonce]
            list.sort()
            sha1 = hashlib.sha1()
            map(sha1.update, list)
            hashcode = sha1.hexdigest()
            print "handle/GET func: hashcode, signature: ", hashcode, signature
            if hashcode == signature:
                return echostr
            else:
                return ""
        except Exception, Argument:
            return Argument

4) 重新啟動成功后(python main.py 80),點擊提交按鈕。若提示”token驗證失敗”, 請認真檢查代碼或網(wǎng)絡(luò)鏈接等。若token驗證成功,會自動返回基本配置的主頁面,點擊啟動按鈕

1.5 重要事情提前交代

接下來,文章準備從兩個簡單的示例入手。

示例一:實現(xiàn)“你說我學(xué)”

示例二:實現(xiàn)“圖尚往來”

兩個簡單的示例后,是一些基礎(chǔ)功能的介紹:素材管理、自定義菜單、群發(fā)。所有的示例代碼是為了簡明的說明問題,避免代碼復(fù)雜化。

在實際中搭建一個安全穩(wěn)定高效的公眾號,建議參考框架如下圖:

e5558202307171127039749.png

主要有三個部分:負責(zé)業(yè)務(wù)邏輯部分的服務(wù)器,負責(zé)對接微信API的API-Proxy服務(wù)器,以及唯一的AccessToken中控服務(wù)器

1)AccessToken中控服務(wù)器:

負責(zé): 提供主動刷新和被動刷新機制來刷新accessToken并存儲(為了防止并發(fā)刷新,注意加并發(fā)鎖),提供給業(yè)務(wù)邏輯有效的accessToken。

優(yōu)點: 避免業(yè)務(wù)邏輯方并發(fā)獲取access_token,避免AccessToken互相覆蓋,提高業(yè)務(wù)功能的穩(wěn)定性。

2)API-Proxy服務(wù)器:

負責(zé):專一與微信API對接,不同的服務(wù)器可以負責(zé)對接不同的業(yè)務(wù)邏輯,更可進行調(diào)用頻率、權(quán)限限制。

優(yōu)點:某臺API-proxy異常,還有其余服務(wù)器支持繼續(xù)提供服務(wù),提高穩(wěn)定性,避免直接暴漏內(nèi)部接口,有效防止惡意攻擊,提高安全性。

2 實現(xiàn)“你問我答”

目的:

1)理解被動消息的含義

2)理解收\發(fā)消息機制

預(yù)實現(xiàn)功能:

粉絲給公眾號一條文本消息,公眾號立馬回復(fù)一條文本消息給粉絲,不需要通過公眾平臺網(wǎng)頁操作。

2.1 接受文本消息

即粉絲給公眾號發(fā)送的文本消息。官方wiki鏈接:接收普通消息

粉絲給公眾號發(fā)送文本消息:“歡迎開啟公眾號開發(fā)者模式”,在開發(fā)者后臺,收到公眾平臺發(fā)送的xml 如下:(下文均隱藏了ToUserName 及 FromUserName 信息)


 
 
 1460537339
 
 
 6272960105994287618

解釋:

createTime 是微信公眾平臺記錄粉絲發(fā)送該消息的具體時間

text: 用于標記該xml 是文本消息,一般用于區(qū)別判斷

歡迎開啟公眾號開發(fā)者模式: 說明該粉絲發(fā)給公眾號的具體內(nèi)容是歡迎開啟公眾號開發(fā)者模式

MsgId: 是公眾平臺為記錄識別該消息的一個標記數(shù)值, 微信后臺系統(tǒng)自動產(chǎn)生

2.2 被動回復(fù)文本消息

即公眾號給粉絲發(fā)送的文本消息,官方wiki鏈接: 被動回復(fù)用戶消息

特別強調(diào):

1) 被動回復(fù)消息,即發(fā)送被動響應(yīng)消息,不同于客服消息接口

2) 它其實并不是一種接口,而是對微信服務(wù)器發(fā)過來消息的一次回復(fù)

3) 收到粉絲消息后不想或者不能5秒內(nèi)回復(fù)時,需回復(fù)“success”字符串(下文詳細介紹)

4) 客服接口在滿足一定條件下隨時調(diào)用

公眾號想回復(fù)給粉絲一條文本消息,內(nèi)容為“test”, 那么開發(fā)者發(fā)送給公眾平臺后臺的xml 內(nèi)容如下:


 
 
 1460541339
 
 

特別備注:

1)ToUserName(接受者)、FromUserName(發(fā)送者) 字段請實際填寫。

2)createtime 只用于標記開發(fā)者回復(fù)消息的時間,微信后臺發(fā)送此消息都是不受這個字段約束。

3)text : 用于標記 此次行為是發(fā)送文本消息 (當然可以是image/voice等類型)。

4)文本換行 ‘\n’。

2.3 回復(fù)success問題

查詢官方wiki 開頭強調(diào): 假如服務(wù)器無法保證在五秒內(nèi)處理回復(fù),則必須回復(fù)“success”或者“”(空串),否則微信后臺會發(fā)起三次重試。

解釋一下為何有這么奇怪的規(guī)定。發(fā)起重試是微信后臺為了盡可以保證粉絲發(fā)送的內(nèi)容開發(fā)者均可以收到。如果開發(fā)者不進行回復(fù),微信后臺沒辦法確認開發(fā)者已收到消息,只好重試。

真的是這樣子嗎?嘗試一下收到消息后,不做任何回復(fù)。在日志中查看到微信后臺發(fā)起了三次重試操作,日志截圖如下:

67ea2202307171127321234.png

三次重試后,依舊沒有及時回復(fù)任何內(nèi)容,系統(tǒng)自動在粉絲會話界面出現(xiàn)錯誤提示“該公眾號暫時無法提供服務(wù),請稍后再試”。

8dce920230717112740827.png

如果回復(fù)success,微信后臺可以確定開發(fā)者收到了粉絲消息,沒有任何異常提示。因此請大家注意回復(fù)success的問題。

2.4 流程圖

c14f1202307171127546034.png

2.5 碼代碼

main.py文件不改變,handle.py 需要增加一下代碼,增加新的文件receive.py, reply.py

1)vim handle.py


# -*- coding: utf-8 -*-# 
# filename: handle.py
import hashlib
import reply
import receive
import web
class Handle(object):
    def POST(self):
        try:
            webData = web.data()
            print "Handle Post webdata is ", webData
            #后臺打日志
            recMsg = receive.parse_xml(webData)
            if isinstance(recMsg, receive.Msg) and recMsg.MsgType == 'text':
                toUser = recMsg.FromUserName
                fromUser = recMsg.ToUserName
                content = "test"
                replyMsg = reply.TextMsg(toUser, fromUser, content)
                return replyMsg.send()
            else:
                print "暫且不處理"
                return "success"
        except Exception, Argment:
            return Argment

2)vim receive.py

# -*- coding: utf-8 -*-#
# filename: receive.py
import xml.etree.ElementTree as ET


def parse_xml(web_data):
    if len(web_data) == 0:
        return None
    xmlData = ET.fromstring(web_data)
    msg_type = xmlData.find('MsgType').text
    if msg_type == 'text':
        return TextMsg(xmlData)
    elif msg_type == 'image':
        return ImageMsg(xmlData)


class Msg(object):
    def __init__(self, xmlData):
        self.ToUserName = xmlData.find('ToUserName').text
        self.FromUserName = xmlData.find('FromUserName').text
        self.CreateTime = xmlData.find('CreateTime').text
        self.MsgType = xmlData.find('MsgType').text
        self.MsgId = xmlData.find('MsgId').text


class TextMsg(Msg):
    def __init__(self, xmlData):
        Msg.__init__(self, xmlData)
        self.Content = xmlData.find('Content').text.encode("utf-8")


class ImageMsg(Msg):
    def __init__(self, xmlData):
        Msg.__init__(self, xmlData)
        self.PicUrl = xmlData.find('PicUrl').text
        self.MediaId = xmlData.find('MediaId').text

3)vim reply.py



# -*- coding: utf-8 -*-#
# filename: reply.py
import time

class Msg(object):
    def __init__(self):
        pass

    def send(self):
        return "success"

class TextMsg(Msg):
    def __init__(self, toUserName, fromUserName, content):
        self.__dict = dict()
        self.__dict['ToUserName'] = toUserName
        self.__dict['FromUserName'] = fromUserName
        self.__dict['CreateTime'] = int(time.time())
        self.__dict['Content'] = content

    def send(self):
        XmlForm = """
            
                
                
                {CreateTime}
                
                
            
            """
        return XmlForm.format(**self.__dict)

class ImageMsg(Msg):
    def __init__(self, toUserName, fromUserName, mediaId):
        self.__dict = dict()
        self.__dict['ToUserName'] = toUserName
        self.__dict['FromUserName'] = fromUserName
        self.__dict['CreateTime'] = int(time.time())
        self.__dict['MediaId'] = mediaId

    def send(self):
        XmlForm = """
            
                
                
                {CreateTime}
                
                
                
                
            
            """
        return XmlForm.format(**self.__dict)

碼好代碼之后,重新啟動程序,sudo python main.py 80。

2.6 在線測試

微信公眾平臺有提供一個在線測試的平臺方便開發(fā)者模擬場景測試代碼邏輯。正如 2.2被動回復(fù)文本消息 交代此被動回復(fù)接口不同于客服接口,測試時也要注意區(qū)別。

在線測試目的在于測試開發(fā)者代碼邏輯是否有誤、是否符合預(yù)期。即便測試成功也不會發(fā)送內(nèi)容給粉絲。所以可以隨意測試。

c342a202307171128395099.png

8eef0202307171128457552.png

測試結(jié)果:

1)”請求失敗”,說明代碼有問題,請檢查代碼邏輯。
d1863202307171128562785.png

2)“請求成功”,然后根據(jù)返回結(jié)果查看是否符合預(yù)期。

e2a75202307171129097073.png

2.7 真實體驗

拿出手機,微信掃描公眾號二維碼,成為自己公眾號的第一個粉絲。公眾號二維碼位置如下圖:

539fc202307171129215702.png

測試如下圖:

7a84d202307171129312982.png

3 實現(xiàn)“圖”尚往來

目的:

1)引入素材管理

2)以文本消息,圖片消息為基礎(chǔ),可自行理解剩余的語音消息、視頻消息、地理消息等

預(yù)實現(xiàn)功能:

接受粉絲發(fā)送的圖片消息,并立馬回復(fù)相同的圖片給粉絲。

3d38e202307171129405448.png

3.1 接收圖片消息

即粉絲給公眾號發(fā)送的圖片消息。官方wiki鏈接:消息管理/接收消息-接受普通消息/ 圖片消息從實例講解,粉絲給公眾號發(fā)送一張圖片消息,在公眾號開發(fā)者后臺接收到的xml如下:


 
 
 1460536575
 
 
 6272956824639273066
 

特別說明:

PicUrl: 這個參數(shù)是微信系統(tǒng)把“粉絲“發(fā)送的圖片消息自動轉(zhuǎn)化成url。 這個url可用瀏覽器打開查看到圖片。

MediaId: 是微信系統(tǒng)產(chǎn)生的id 用于標記該圖片,詳情可參考wiki素材管理/獲取臨時素材

3.2 被動回復(fù)圖片消息

即公眾號給粉絲發(fā)送的圖片消息。官方wiki鏈接:消息管理/發(fā)送消息-被動回復(fù)用戶消息/ 圖片消息

特別說明:

1) 被動回復(fù)消息,即發(fā)送被動響應(yīng)消息,不同于客服消息接口

2) 它其實并不是一種接口,而是對微信服務(wù)器發(fā)過來消息的一次回復(fù)

3) 收到粉絲消息后不想或者不能5秒內(nèi)回復(fù)時,需回復(fù)“success”字符串(下文詳細介紹)

4) 客服接口在滿足一定條件下隨時調(diào)用

開發(fā)者發(fā)送給微信后臺的xml 如下:


 
 
 1460536576
 
 
 
 

這里填寫的MediaId的內(nèi)容,其實就是粉絲的發(fā)送圖片的原MediaId,所以粉絲收到了一張一模一樣的原圖。 如果想回復(fù)粉絲其它圖片怎么呢?

1) 新增素材,請參考 新增臨時素材 或者 新增永久素材

2) 獲取其MediaId,請參考 獲取臨時素材MediaID 或者 獲取永久素材MediaID

3.3 流程圖

d2171202307171130013692.png

3.4 碼代碼

只顯示更改的代碼部分,其余部分參考上小節(jié),在線測試,真實體驗,回復(fù)空串,請參考 實現(xiàn)"你問我答"。 vim handle.py

# -*- coding: utf-8 -*-
# filename: handle.py
import hashlib
import reply
import receive
import web

class Handle(object):
    def POST(self):
        try:
            webData = web.data()
            print "Handle Post webdata is ", webData   #后臺打日志
            recMsg = receive.parse_xml(webData)
            if isinstance(recMsg, receive.Msg):
                toUser = recMsg.FromUserName
                fromUser = recMsg.ToUserName
                if recMsg.MsgType == 'text':
                    content = "test"
                    replyMsg = reply.TextMsg(toUser, fromUser, content)
                    return replyMsg.send()
                if recMsg.MsgType == 'image':
                    mediaId = recMsg.MediaId
                    replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)
                    return replyMsg.send()
                else:
                    return reply.Msg().send()
            else:
                print "暫且不處理"
                return reply.Msg().send()
        except Exception, Argment:
            return Argment

4 AccessToken

AccessToken 的意義請參考公眾平臺wiki介紹。

4.1 查看appid及appsecret

公眾平臺官網(wǎng)查看, 其中AppSecret 不點擊重置時候,則一直保持不變。

8f5b8202307171130205274.png

4.2 獲取accessToken

4.2.1臨時方法獲取

為了方便先體驗其他接口,可以臨時通過在線測試 或者 瀏覽器獲取accessToken。

bd89f20230717113030561.png

4.2.2 接口獲取

詳情請見公眾平臺wiki

特別強調(diào):

1) 第三方需要一個access_token獲取和刷新的中控服務(wù)器。

2) 并發(fā)獲取access_token會導(dǎo)致AccessToken互相覆蓋,影響具體的業(yè)務(wù)功能

4.3 碼代碼

再次重復(fù)說明,下面代碼只是為了簡單說明接口獲取方式。實際中并不推薦,尤其是業(yè)務(wù)繁重的公眾號,更需要中控服務(wù)器,統(tǒng)一的獲取accessToken。

vim basic.py

# -*- coding: utf-8 -*-
# filename: basic.py
import urllib
import time
import json
class Basic:
    def __init__(self):
        self.__accessToken = ''
        self.__leftTime = 0

    def __real_get_access_token(self):
        appId = "xxxxx"
        appSecret = "xxxxx"
        postUrl = ("https://api.weixin.qq.com/cgi-bin/token?grant_type="
                   "client_credential&appid=%s&secret=%s" % (appId, appSecret))
        urlResp = urllib.urlopen(postUrl)
        urlResp = json.loads(urlResp.read())
        self.__accessToken = urlResp['access_token']
        self.__leftTime = urlResp['expires_in']

    def get_access_token(self):
        if self.__leftTime < 10:
            self.__real_get_access_token()
        return self.__accessToken

    def run(self):
        while(True):
            if self.__leftTime > 10:
                time.sleep(2)
                self.__leftTime -= 2
            else:
                self.__real_get_access_token()

5 臨時素材

公眾號經(jīng)常有需要用到一些臨時性的多媒體素材的場景,例如在使用接口特別是發(fā)送消息時,對多媒體文件、多媒體消息的獲取和調(diào)用等操作,是通過MediaID來進行的。譬如實現(xiàn)“圖”尚往來中,粉絲給公眾號發(fā)送圖片消息,便產(chǎn)生一臨時素材。

因為永久素材有數(shù)量的限制,但是公眾號又需要臨時性使用一些素材,因而產(chǎn)生了臨時素材。這類素材不在微信公眾平臺后臺長期存儲,所以在公眾平臺官網(wǎng)的素材管理中查詢不到,但是可以通過接口對其操作。

其他詳情請以公眾平臺官網(wǎng)wiki介紹為依據(jù)。

5.1 新建臨時素材

接口詳情請依據(jù)wiki介紹。提供參考代碼如何上傳素材作為臨時素材,供其它接口使用。

vim media.py 編寫完成之后,直接運行media.py 即可上傳臨時素材。

# -*- coding: utf-8 -*-
# filename: media.py
from basic import Basic
import urllib2
import poster.encode
from poster.streaminghttp import register_openers


class Media(object):
    def __init__(self):
        register_openers()
    
    # 上傳圖片
    def upload(self, accessToken, filePath, mediaType):
        openFile = open(filePath, "rb")
        param = {'media': openFile}
        postData, postHeaders = poster.encode.multipart_encode(param)

        postUrl = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s" % (
            accessToken, mediaType)
        request = urllib2.Request(postUrl, postData, postHeaders)
        urlResp = urllib2.urlopen(request)
        print urlResp.read()

if __name__ == '__main__':
    myMedia = Media()
    accessToken = Basic().get_access_token()
    filePath = "D:/code/mpGuide/media/test.jpg"  # 請按實際填寫
    mediaType = "image"
    myMedia.upload(accessToken, filePath, mediaType)

5.2 獲取臨時素材MediaID

臨時素材的MediaID 沒有提供特定的接口進行統(tǒng)一查詢,因此有倆種方式

1) 通過接口上次的臨時素材,在調(diào)用成功的情況下,從返回JSON數(shù)據(jù)中提取MediaID,可臨時使用

2) 粉絲互動中的臨時素材,可從xml 數(shù)據(jù)提取MediaID,可臨時使用

5.3 下載臨時素材

5.3.1 手工體驗

開發(fā)者如何保存粉絲發(fā)送的圖片呢?接口文檔:獲取臨時素材接口,為方便理解,從最簡單瀏覽器獲取素材的方法入手,根據(jù)實際情況,瀏覽器輸入網(wǎng)址: https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID (自行替換數(shù)據(jù)) ACCESS_TOKEN 如 "AccessToken"章節(jié)講解 MEDIA_ID 如 圖尚往來/接受圖片消息xml中的MediaId 講解 只要數(shù)據(jù)正確,則會下載圖片到本地,如下圖:

c51a6202307171131036679.png

75024202307171131075263.png

5.3.2接口獲取

現(xiàn)在已經(jīng)理解這個接口的功能了,只剩碼代碼了。

vim media.py

# -*- coding: utf-8 -*-
# filename: media.py
import urllib2
import json
from basic import Basic


class Media(object):
    def get(self, accessToken, mediaId):
        postUrl = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s" % (
            accessToken, mediaId)
        urlResp = urllib2.urlopen(postUrl)

        headers = urlResp.info().__dict__['headers']
        if ('Content-Type: application/json\r\n' in headers) or ('Content-Type: text/plain\r\n' in headers):
            jsonDict = json.loads(urlResp.read())
            print jsonDict
        else:
            buffer = urlResp.read()  # 素材的二進制
            mediaFile = file("test_media.jpg", "wb")
            mediaFile.write(buffer)
            print "get successful"


if __name__ == '__main__':
    myMedia = Media()
    accessToken = Basic().get_access_token()
    mediaId = "2ZsPnDj9XIQlGfws31MUfR5Iuz-rcn7F6LkX3NRCsw7nDpg2268e-dbGB67WWM-N"
    myMedia.get(accessToken, mediaId)

直接運行 media.py 即可把想要的素材下載下來,其中圖文消息類型的,會直接在屏幕輸出json數(shù)據(jù)段。

6 永久素材

6.1 新建永久素材的方式

6.1.1 手工體驗

公眾號官網(wǎng)的素材管理新增素材。補充一點,公眾平臺只以MediaID區(qū)分素材,MediaID不等于素材的文件名。MediaID只能通過接口查詢,公眾平臺官網(wǎng)看到的是素材的文件名,如下圖:

4fbd7202307171131255137.png

6.1.2 新增永久素材

新增永久素材接口(詳情見wiki),跟新增臨時素材的操作差不多,使用url不一樣而已,這里避免重復(fù),以新增永久圖文素材接口為例,新增其他類型的素材請參考新增臨時素材代碼。

vim material.py

# -*- coding: utf-8 -*-
# filename: material.py
import urllib2
import json
from basic import Basic

class Material(object):
    # 上傳圖文
    def add_news(self, accessToken, news):
        postUrl = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=%s" % accessToken
        urlResp = urllib2.urlopen(postUrl, news)
        print urlResp.read()

if __name__ == '__main__':
    myMaterial = Material()
    accessToken = Basic().get_access_token()
    news = (
        {
            "articles":
            [
                {
                    "title": "test",
                    "thumb_media_id": "X2UMe5WdDJSS2AS6BQkhTw9raS0pBdpv8wMZ9NnEzns",
                    "author": "vickey",
                    "digest": "",
                    "show_cover_pic": 1,
                    "content": "

\"\"
\"\"

", "content_source_url": "", } ] }) # news 是個dict類型,可通過下面方式修改內(nèi)容 #news['articles'][0]['title'] = u"測試".encode('utf-8') # print news['articles'][0]['title'] news = json.dumps(news, ensure_ascii=False) myMaterial.add_news(accessToken, news)

6.2 獲取永久素材MediaID

1) 通過新增永久素材接口(詳情見wiki)新增素材時,保存MediaID

2) 通過獲取永久素材列表(下文介紹) 的方式獲取素材信息,從而得到MediaID

6.3 獲取素材列表

官方wiki鏈接:獲取素材列表特別說明:此接口只是批量拉取素材信息,不是一次性拉去所有素材的信息,所以可以理解offset字段的含義了吧。

vim material.py

# -*- coding: utf-8 -*-
# filename: material.py
import urllib2
import json
import poster.encode
from poster.streaminghttp import register_openers
from basic import Basic

class Material(object):
    def __init__(self):
        register_openers()
    #上傳
    def upload(self, accessToken, filePath, mediaType):
        openFile = open(filePath, "rb")
        fileName = "hello"
        param = {'media': openFile, 'filename': fileName}
        #param = {'media': openFile}
        postData, postHeaders = poster.encode.multipart_encode(param)

        postUrl = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s&type=%s" % (accessToken, mediaType)
        request = urllib2.Request(postUrl, postData, postHeaders)
        urlResp = urllib2.urlopen(request)
        print urlResp.read()
    #下載
    def get(self, accessToken, mediaId):
        postUrl = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=%s" % accessToken
        postData = "{ \"media_id\": \"%s\" }" % mediaId
        urlResp = urllib2.urlopen(postUrl, postData)
        headers = urlResp.info().__dict__['headers']
        if ('Content-Type: application/json\r\n' in headers) or ('Content-Type: text/plain\r\n' in headers):
            jsonDict = json.loads(urlResp.read())
            print jsonDict
        else:
            buffer = urlResp.read()  # 素材的二進制
            mediaFile = file("test_media.jpg", "wb")
            mediaFile.write(buffer)
            print "get successful"
    #刪除
    def delete(self, accessToken, mediaId):
        postUrl = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=%s" % accessToken
        postData = "{ \"media_id\": \"%s\" }" % mediaId
        urlResp = urllib2.urlopen(postUrl, postData)
        print urlResp.read()
    
    #獲取素材列表
    def batch_get(self, accessToken, mediaType, offset=0, count=20):
        postUrl = ("https://api.weixin.qq.com/cgi-bin/material"
               "/batchget_material?access_token=%s" % accessToken)
        postData = ("{ \"type\": \"%s\", \"offset\": %d, \"count\": %d }"
                    % (mediaType, offset, count))
        urlResp = urllib2.urlopen(postUrl, postData)
        print urlResp.read()

if __name__ == '__main__':
    myMaterial = Material()
    accessToken = Basic().get_access_token()
    mediaType = "news"
    myMaterial.batch_get(accessToken, mediaType)

6.4 刪除永久素材

如果我想刪除掉 20160102.jpg 這張圖片,除了官網(wǎng)直接操作,也可以使用接口: 刪除永久素材 接口文檔。

首先需要知道該圖片的mediaID,方法上小節(jié)已講述。代碼可參考上小節(jié):Material().delete() 接口 調(diào)用接口成功后,在公眾平臺官網(wǎng)素材管理的圖片中,查詢不到已刪除的圖片。

f39f7202307171131504249.png

7 自定義菜單

自定義菜單意義作用請參考創(chuàng)建接口 介紹。

目標:三個菜單欄,體驗click、view、media_id 三種類型的菜單按鈕,其他類型在本小節(jié)學(xué)習(xí)之后,自行請查詢公眾平臺wiki說明領(lǐng)悟。

7.1 創(chuàng)建菜單界面

1)根據(jù)公眾平臺wiki 給的json 數(shù)據(jù)編寫代碼,其中涉及media_id部分請閱讀"永久素材"章節(jié)。

vim menu.py

# -*- coding: utf-8 -*-
# filename: menu.py
import urllib
from basic import Basic

class Menu(object):
    def __init__(self):
        pass
    def create(self, postData, accessToken):
        postUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s" % accessToken
        if isinstance(postData, unicode):
            postData = postData.encode('utf-8')
        urlResp = urllib.urlopen(url=postUrl, data=postData)
        print urlResp.read()

    def query(self, accessToken):
        postUrl = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s" % accessToken
        urlResp = urllib.urlopen(url=postUrl)
        print urlResp.read()

    def delete(self, accessToken):
        postUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s" % accessToken
        urlResp = urllib.urlopen(url=postUrl)
        print urlResp.read()
        
    #獲取自定義菜單配置接口
    def get_current_selfmenu_info(self, accessToken):
        postUrl = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=%s" % accessToken
        urlResp = urllib.urlopen(url=postUrl)
        print urlResp.read()

if __name__ == '__main__':
    myMenu = Menu()
    postJson = """
    {
        "button":
        [
            {
                "type": "click",
                "name": "開發(fā)指引",
                "key":  "mpGuide"
            },
            {
                "name": "公眾平臺",
                "sub_button":
                [
                    {
                        "type": "view",
                        "name": "更新公告",
                        "url": "http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1418702138&token=&lang=zh_CN"
                    },
                    {
                        "type": "view",
                        "name": "接口權(quán)限說明",
                        "url": "http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1418702138&token=&lang=zh_CN"
                    },
                    {
                        "type": "view",
                        "name": "返回碼說明",
                        "url": "http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433747234&token=&lang=zh_CN"
                    }
                ]
            },
            {
                "type": "media_id",
                "name": "旅行",
                "media_id": "z2zOokJvlzCXXNhSjF46gdx6rSghwX2xOD5GUV9nbX4"
            }
          ]
    }
    """
    accessToken = Basic().get_access_token()
    #myMenu.delete(accessToken)
    myMenu.create(postJson, accessToken)

2)在騰訊云服務(wù)器上執(zhí)行命令:python menu.py。

3)查看: 重新關(guān)注公眾號后即可看到新創(chuàng)建菜單界面,題外話,如果不重新關(guān)注,公眾號界面也會自動更改,但有時間延遲。

如下圖所示,點擊子菜單“更新公告“(view類型),彈出網(wǎng)頁(pc版本)

048be202307171132101867.png

點擊旅行(media_id類型),公眾號顯示了一篇圖文消息,如下圖所示:

4d7c4202307171132205488.png

點擊開發(fā)指引(click類型),發(fā)現(xiàn)公眾號系統(tǒng)提示:“該公眾號暫時無法提供服務(wù)“。

ea7f9202307171132306825.png

7.2 完善菜單功能

查看公眾平臺自定義菜單自定義菜單事件推送 后,可知:點擊click類型button,微信后臺會推送一個event類型的xml 給開發(fā)者。

顯然,click類型的還需要開發(fā)者進一步完善后臺代碼邏輯,增加對自定義菜單事件推送的相應(yīng)。

7.2.1 流程圖

b17c0202307171132385926.png

7.2.2碼代碼

  1. vim handle.py (修改)
# -*- coding: utf-8 -*-
# filename: handle.py
import reply
import receive
import web

class Handle(object):
    def POST(self):
        try:
            webData = web.data()
            print "Handle Post webdata is ", webData  # 后臺打日志
            recMsg = receive.parse_xml(webData)
            if isinstance(recMsg, receive.Msg):
                toUser = recMsg.FromUserName
                fromUser = recMsg.ToUserName
                if recMsg.MsgType == 'text':
                    content = "test"
                    replyMsg = reply.TextMsg(toUser, fromUser, content)
                    return replyMsg.send()
                if recMsg.MsgType == 'image':
                    mediaId = recMsg.MediaId
                    replyMsg = reply.ImageMsg(toUser, fromUser, mediaId)
                    return replyMsg.send()
            if isinstance(recMsg, receive.EventMsg):
                toUser = recMsg.FromUserName
                fromUser = recMsg.ToUserName
                if recMsg.Event == 'CLICK':
                    if recMsg.Eventkey == 'mpGuide':
                        content = u"編寫中,尚未完成".encode('utf-8')
                        replyMsg = reply.TextMsg(toUser, fromUser, content)
                        return replyMsg.send()
            print "暫且不處理"
            return reply.Msg().send()
        except Exception, Argment:
            return Argment

2)vim receive.py (修改)

# -*- coding: utf-8 -*-
# filename: receive.py
import xml.etree.ElementTree as ET

def parse_xml(web_data):
    if len(web_data) == 0:
        return None
    xmlData = ET.fromstring(web_data)
    msg_type = xmlData.find('MsgType').text
    if msg_type == 'event':
        event_type = xmlData.find('Event').text
        if event_type == 'CLICK':
            return Click(xmlData)
        #elif event_type in ('subscribe', 'unsubscribe'):
            #return Subscribe(xmlData)
        #elif event_type == 'VIEW':
            #return View(xmlData)
        #elif event_type == 'LOCATION':
            #return LocationEvent(xmlData)
        #elif event_type == 'SCAN':
            #return Scan(xmlData)
    elif msg_type == 'text':
        return TextMsg(xmlData)
    elif msg_type == 'image':
        return ImageMsg(xmlData)

class EventMsg(object):
    def __init__(self, xmlData):
        self.ToUserName = xmlData.find('ToUserName').text
        self.FromUserName = xmlData.find('FromUserName').text
        self.CreateTime = xmlData.find('CreateTime').text
        self.MsgType = xmlData.find('MsgType').text
        self.Event = xmlData.find('Event').text
class Click(EventMsg):
    def __init__(self, xmlData):
        EventMsg.__init__(self, xmlData)
        self.Eventkey = xmlData.find('EventKey').text

7.3 體驗

編譯好代碼后,重新啟動服務(wù),(sudo python main.py 80),view類型、media_id類型的本身就很容易實現(xiàn),現(xiàn)在重點看一下click類型的菜單按鈕。

微信掃碼成為公眾號的粉絲,點擊菜單按鈕“開發(fā)指引”。

查看后臺日志,發(fā)現(xiàn)接收到一條xml,如截圖:

a23b520230717113312812.png
公眾號的后臺代碼設(shè)置對該事件的處理是回復(fù)一條內(nèi)容為“編寫之中”的文本消息,因此公眾號發(fā)送了一條文本消息給我,如圖:

f8a33202307171133236311.png

好啦,到此,目標已實現(xiàn)。對于自定義菜單其他類型,均同理可操作。

8 關(guān)于反饋問題

是程序肯定有bug,所以在使用開放平臺過程中,肯定會遇見各種各樣的問題,可能是自己的坑,也可能是微信團隊的鍋。當自己查自己代碼千千遍,依舊沒有發(fā)現(xiàn)問題時候,可以通過 #公眾號社區(qū) 發(fā)帖交流、騰訊客服等等渠道,請求微信團隊的幫助。如何高效快速的得到幫助呢?下面強調(diào)三個要點:

1)簡明扼要的描述清楚場景以及遇見問題,描述過程中盡可能使用wiki上的名稱,譬如自定義菜單,素材管理等專有名詞,不然開發(fā)根本不知道你在說什么。

2)提供賬號信息:AppID(登錄公眾平臺官網(wǎng)->基本配置),若牽扯粉絲提供粉絲的OpenID。

3)提供bug的發(fā)生時間,至少要以小時為單位(年-月-日-小時),當然越具體越容易查明問題。


請登錄后查看

CRMEB-慕白寒窗雪 最后編輯于2023-07-17 17:42:30

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認正序 回復(fù)倒序 點贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
970
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動態(tài) 精選推薦 首頁頭條 首頁動態(tài) 首頁推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動獲取的帖子內(nèi)容,不準確時需要手動修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認打賞

微信登錄/注冊

切換手機號登錄

{{ bind_phone ? '綁定手機' : '手機登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服