国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營(yíng)銷資訊 > 網(wǎng)站運(yùn)營(yíng) > Flask Web開發(fā) – 搭建微信公眾號(hào)后臺(tái)系統(tǒng)

Flask Web開發(fā) – 搭建微信公眾號(hào)后臺(tái)系統(tǒng)

時(shí)間:2022-08-07 18:39:01 | 來源:網(wǎng)站運(yùn)營(yíng)

時(shí)間:2022-08-07 18:39:01 來源:網(wǎng)站運(yùn)營(yíng)



Python酷的文章一般在 https://pythonlibrary.net/ 網(wǎng)頁上首發(fā),而隨后同步的我們的微信,然后由于我們的文章都是包含大量代碼的干貨文章,對(duì)于微信閱讀其實(shí)效果并不是特別理想,因此我們后來將微信公眾號(hào)的方向轉(zhuǎn)為為訂閱用戶提供文章摘要,新文章發(fā)布提醒,以及文章搜索的功能,未來我們還考慮增加例如智能對(duì)話,或者AI助手等等功能,讀者如果有更好的意見和建議也可以發(fā)送給我們。公眾號(hào)自帶的后臺(tái)管理就沒辦法滿足要求了,因此我們使用Flask搭建了微信公眾號(hào)的后臺(tái)系統(tǒng),同時(shí)我們認(rèn)為這也是一個(gè)很好的機(jī)會(huì)來給大家講解如何使用Flask進(jìn)行Web開發(fā)和后端開發(fā)。

為什么要用Flask

Flask是一個(gè)在Python世界上非常流行的Web開發(fā)框架,它非常的微型,不像Django提供了很多開箱即用的功能,F(xiàn)lask本身僅僅提供了請(qǐng)求,路由等等核心功能,用戶可以自由的在開源社區(qū)選取高質(zhì)量的Flask擴(kuò)展來組合實(shí)現(xiàn)想要的功能,對(duì)于新手開發(fā)者可以很快的上手,并從中學(xué)習(xí)到更多通用的知識(shí),如果說學(xué)習(xí)Django就是如何學(xué)習(xí)使用Django來搭建Web應(yīng)用的話,學(xué)習(xí)Flask是學(xué)習(xí)使用Python來搭建Web應(yīng)用。對(duì)于資深開發(fā)人員也可以保質(zhì)保量的完成項(xiàng)目,而且我們?cè)?跟我一起讀源碼 – 如何閱讀開源代碼 的文章中也說過,這個(gè)項(xiàng)目的源代碼實(shí)現(xiàn)非常的優(yōu)雅,有著很大的社區(qū)基礎(chǔ)和支持。

考慮到看這篇文章的讀者可能大多是剛?cè)腴TPython Web開發(fā),結(jié)合基于以上Flask的優(yōu)勢(shì),我們使用了Flask作為微信公眾號(hào)后臺(tái)的開發(fā)框架。

讀者將學(xué)到什么

在本篇文章中我們不會(huì)從一個(gè)Hello World的示例講起,而是以Flask為基礎(chǔ),介紹一個(gè)通用的Flask項(xiàng)目結(jié)構(gòu),讀者能夠?qū)⑦@個(gè)項(xiàng)目結(jié)構(gòu)應(yīng)用到自己的 Python后端開發(fā) 大型項(xiàng)目中,同時(shí)在這個(gè)結(jié)構(gòu)中,完成我們微信公眾號(hào)后臺(tái)提供的功能,包括信息收發(fā)(接收和回復(fù))以及文章資源搜索。因此需要讀者對(duì)Web開發(fā)的基本概念有一些認(rèn)識(shí),如果你還從來沒有讀過或者運(yùn)行過任何一個(gè)Python Web框架的Hello World,或者對(duì)Python Web開發(fā)沒有任何認(rèn)知,建議讀者先閱讀 數(shù)據(jù)可視化 – 利用Bokeh和Bottle.py在網(wǎng)上展示你的數(shù)據(jù) 這篇文章(文章第三章節(jié)可以幫著你掌握這些基礎(chǔ)知識(shí))。

在本篇文章中,我們涵蓋的技術(shù)點(diǎn)包括

認(rèn)識(shí)項(xiàng)目

在學(xué)習(xí)如何搭建Python Web項(xiàng)目結(jié)構(gòu)之前,我們先來介紹一下本項(xiàng)目的框架。用戶向我們的微信公眾號(hào)發(fā)送消息,然后公眾號(hào)會(huì)使用Post方法調(diào)起我們開發(fā)的Flask后臺(tái),在Flask后端,我們會(huì)驗(yàn)證接收到的消息是否合法,如果合法則去文章緩存中查詢是否有滿足用戶查詢的文章,如果有則返回文章鏈接,如果沒有則返回幫助信息。

另外,為了提升用戶體驗(yàn),加快相應(yīng)速度,我們?cè)?span >https://pythonlibrary.net發(fā)布的文章會(huì)被Flask后端周期性的拉取并做緩存。

為了滿足上邊描述的這些功能,在這個(gè)項(xiàng)目中我們主要用到的第三方庫有

所有的需求都放在項(xiàng)目的requirements里邊了,大家可以使用pip一鍵安裝。(使用requirements文件來放置Python項(xiàng)目用到的依賴是一個(gè)非常好的編碼習(xí)慣)

項(xiàng)目結(jié)構(gòu)

我們采用的代碼文件夾結(jié)構(gòu)如下,其中

│ config.py│ manage.py│ requirements.txt├─app│ │ apiv1.py│ │ __init__.py│ │ │ ├─apis│ │ │ __init__.py│ │ │ │ │ ├─chat│ │ │ │ ai.py│ │ │ │ receive.py│ │ │ │ reply.py│ │ │ │ resources.py│ │ │ │ __init__.py│ │ │ │ ├─core│ │ │ articles.py│ ├─requirements│ common.txt│ dev.txt│ prod.txt

配置文件和讀取

在做Web項(xiàng)目的時(shí)候,我們會(huì)有各種各樣的配置信息,用來控制項(xiàng)目的運(yùn)行,例如我們需要設(shè)置數(shù)據(jù)庫的位置,設(shè)置一些應(yīng)用的Token等等,在源碼中我們將這些配置集中起來,更容易管理和修改,尤其是在Web開發(fā)中,有生產(chǎn)環(huán)境和開發(fā)環(huán)境,用到的設(shè)置可能會(huì)不一致,在一個(gè)統(tǒng)一的配置文件中就可以很好的管理了。

我們項(xiàng)目中的config.py就是我了這個(gè)目的而實(shí)現(xiàn)的,在文件中,有一個(gè)叫做Config的類,它包含兩個(gè)類方法start_hook和init_app,start_hook會(huì)在創(chuàng)建Flask App對(duì)象之前被調(diào)用,而init_app會(huì)在App對(duì)象被創(chuàng)建好以后進(jìn)行一些必要的初始化,它接收Flask App對(duì)象作為參數(shù)。

class Config(object): @classmethod def start_hook(cls): pass @classmethod def init_app(cls, app): pass我們其他的配置都是集成自這個(gè)基礎(chǔ)的Config類,在我們這個(gè)項(xiàng)目,有LocalmachineConfig,ProductionConfig和DockerConfig三種配置,并形成一個(gè)配置字典。

config = { 'development': LocalmachineConfig, 'production': DockerConfig, 'default': LocalmachineConfig}其中LocalmachineConfig為我們的開發(fā)環(huán)境配置,DockerConfig為我們的生成環(huán)境配置,因?yàn)槲覀兪褂昧薉ocker作為部署方式,而DockerConfig又繼承自ProductionConfig,默認(rèn)的環(huán)境為開發(fā)環(huán)境,也就是說當(dāng)我們調(diào)用 python manage.py run 來運(yùn)行應(yīng)用的時(shí)候,默認(rèn)是運(yùn)行開發(fā)環(huán)境,只有當(dāng)我們?cè)诃h(huán)境變量中設(shè)置FLASK_CONFIG=production 才會(huì)啟動(dòng)生產(chǎn)環(huán)境。

接下來我們以生產(chǎn)環(huán)境配置ProductionConfig為例來看一下,具體怎么來添加和設(shè)置配置信息。

class ProductionConfig(Config): DEBUG = False WEIWIN_TOKEN = 'foobar' CONFIG_DIR = '/usr/config' SITEMAP_URL = "http://wordpress/post-sitemap.xml" @classmethod def init_app(cls, app): app.logger.removeHandler(default_handler) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s') # TODO - split log files if size is too big file_handler = RotatingFileHandler("/var/log/" + 'pythonlibrary_api_log.log', maxBytes=1024 * 1024 * 100, backupCount=10) file_handler.setLevel(logging.INFO) file_handler.setFormatter(formatter) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO)所有的配置可以以成員變量的方式來指定,比如微信后臺(tái)的授權(quán)碼,可以用WEIWIN_TOKEN來指定,我們的需要周期拉取的網(wǎng)站地址由SITEMAP_URL 來指定。

這些配置信息都可以通過Flask的 current_app對(duì)象來獲取,例如,可以通過

current_app.config.get('SITEMAP_URL')來獲取到SITEMAP_URL配置信息

而在init_app中,可以對(duì)一些必要的需要初始化的功能進(jìn)行初始化。在這里,我們將Flask內(nèi)置的logger的格式進(jìn)行了修改,同時(shí),將日志文件輸出到/var/log/pythonlibrary_api_log.log文件中,如果不做配置的話,默認(rèn)日志會(huì)打印到控制臺(tái)。

周期爬取文章

在Web應(yīng)用中,定時(shí)的爬取其他來源并進(jìn)行緩存也是一個(gè)很常見的應(yīng)用場(chǎng)景,在我們這個(gè)項(xiàng)目中,我們需要從https://pythonlibray.net中定期的抓取文章并保存,從而在用戶進(jìn)行搜索的時(shí)候能夠快速響應(yīng)。通常這些周期獲取到的數(shù)據(jù)會(huì)保存到數(shù)據(jù)庫,或者為了性能會(huì)保存到Redis中,但是我們這個(gè)項(xiàng)目由于數(shù)據(jù)量較小,我們進(jìn)行了簡(jiǎn)化,這些數(shù)據(jù)就直接放到內(nèi)存的數(shù)據(jù)結(jié)構(gòu)中。

為了實(shí)現(xiàn)定時(shí)周期性的運(yùn)行抓取任務(wù),我們使用了 apscheduler 這個(gè)庫,我們可以利用這個(gè)庫,來定義自己的周期任務(wù),它會(huì)安裝我們?cè)O(shè)定好的周期策略來運(yùn)行已經(jīng)定義好的任務(wù),也就是爬取數(shù)據(jù)的任務(wù)。

我們將這部分的實(shí)現(xiàn)放在了app/init.py中

def create_app(config_name): scheduler = BackgroundScheduler() config[config_name].start_hook() app = Flask(__name__) app.register_blueprint(api_v1) app.config.from_object(config[config_name]) # Read config from config.py app.config['RESTFUL_JSON'] = { 'ensure_ascii': False } # Ugly implementation for saving scheduler object and articles cache setattr(app, 'articles', None) setattr(app, 'ap_scheduler', scheduler) post_sitemap = app.config.get('SITEMAP_URL') # run task right away at the startup update_articles(post_sitemap, app) app.ap_scheduler.add_job(update_articles, 'interval', [post_sitemap, app], days=10) app.ap_scheduler.start() config[config_name].init_app(app) # call init_app from config return appcreate_app這個(gè)函數(shù)主要是用來創(chuàng)建Flask App的,因此如上一節(jié)所講解,在這個(gè)函數(shù)中,我們首先是調(diào)用了Config類的start_hook方法,然后創(chuàng)建了Flask App,再然后,調(diào)用了Config類的init_app方法,最后將這個(gè)app返回。

除此之外,我們還在這里定義了一個(gè)后臺(tái)任務(wù)管理器,并向里邊添加了一個(gè)update_articles任務(wù),該任務(wù)的執(zhí)行周期為10天,同時(shí)在啟動(dòng)任務(wù)之前,我們強(qiáng)制運(yùn)行了一遍這個(gè)任務(wù),因?yàn)槟J(rèn)情況下apscheduler 第一次啟動(dòng)是不會(huì)運(yùn)行任務(wù)的,只有當(dāng)周期到了以后才會(huì)運(yùn)行,因?yàn)槲覀儾捎脙?nèi)存數(shù)據(jù)結(jié)構(gòu)保存爬取的數(shù)據(jù),所以Web應(yīng)用第一次運(yùn)行的時(shí)候,內(nèi)存數(shù)據(jù)結(jié)構(gòu)里邊是空的,我們又不想等待那么長(zhǎng)的時(shí)間才能拿到數(shù)據(jù)來服務(wù)用戶,所以,需要手動(dòng)運(yùn)行一遍這個(gè)任務(wù)來爬取一些數(shù)據(jù)進(jìn)來。

update_articles(post_sitemap, app) app.ap_scheduler.add_job(update_articles, 'interval', [post_sitemap, app], days=10)app.ap_scheduler.start()另外,大家會(huì)問,那么內(nèi)存數(shù)據(jù)結(jié)構(gòu)在哪里,爬取到的數(shù)據(jù)存到哪里了?我們希望這些數(shù)據(jù)能夠被 Web應(yīng)用全局的訪問,因此為了簡(jiǎn)化代碼,我們使用了一個(gè)較為簡(jiǎn)單的實(shí)現(xiàn),如下邊代碼,我們?cè)贔lask App上邊創(chuàng)建了一個(gè)articles屬性來保存爬取到的數(shù)據(jù),因?yàn)镕lask App是全局可以通過current_app來訪問的,所以我們的article也是全局可以訪問的,在稍微大一點(diǎn)的正式項(xiàng)目中不建議用這種方法,而是要分開定義一個(gè)單獨(dú)的數(shù)據(jù)存儲(chǔ)類。

# Ugly implementation for saving scheduler object and articles cache setattr(app, 'articles', None)而在core/articles.py文件中對(duì)于update_articles這個(gè)周期任務(wù)的實(shí)現(xiàn)為:

def update_articles(post_sitemap, app): articles = get_all_articles(post_sitemap) app.logger.info('Posts updated at: %s' % datetime.now()) setattr(app, 'articles', articles)在這里通過get_all_articles爬取到的數(shù)據(jù),通過setattr設(shè)置給Flask App的articles屬性來保存。有了文章以后,我們?cè)趺锤⑿殴娞?hào)后臺(tái)進(jìn)行對(duì)接呢?答案就是通過API,我們的Flask后端設(shè)計(jì)一個(gè)API,然后微信公眾號(hào)可以調(diào)用這個(gè)后端,接下來我們就介紹這一部分代碼。

API 設(shè)計(jì)

在前后端分離的Web開發(fā)中,前端和后端的交互是通過API實(shí)現(xiàn)的,跟我們這個(gè)項(xiàng)目的概念是一樣的,因此我們這里講解的技術(shù)在開發(fā)有前端的項(xiàng)目中是通用的。而API的規(guī)范在設(shè)計(jì)和實(shí)現(xiàn)API的時(shí)候是很重要的,通常比較流行的規(guī)范是REST,按照這個(gè)規(guī)范定義出來的API會(huì)比較規(guī)范,在和團(tuán)隊(duì)其他成員進(jìn)行溝通,或者需要文檔化的時(shí)候都會(huì)有一個(gè)統(tǒng)一的標(biāo)準(zhǔn),我們簡(jiǎn)單的借鑒了這個(gè)思想,但是由于API需要滿足微信公眾號(hào)的要求,因此可能不會(huì)完全滿足REST規(guī)范要求,REST規(guī)范也很簡(jiǎn)單,當(dāng)你學(xué)會(huì)了怎么設(shè)計(jì)API以后,來使用REST規(guī)范也就很容易了。

在本項(xiàng)目中,我們使用了flask_restx這個(gè)庫來輔助我們現(xiàn)在REST規(guī)范的API。

版本

在REST規(guī)范中,要求我們的API要有版本管理,因?yàn)槲覀兾磥頃?huì)有升級(jí)API的可能,因此,使用版本管理,可以讓API使用者能夠開發(fā)更加健壯的代碼,不會(huì)因?yàn)锳PI的升級(jí)導(dǎo)致API使用者的代碼失效,或者導(dǎo)致軟件不可用。API的版本體現(xiàn)在API的url中,一個(gè)符合REST版本管理要求的API長(zhǎng)這個(gè)樣子 http://domain/api/v1/xxxxxx

其中前半部分http://domain/api/v1/是固定的,里邊包含了版本號(hào)v1,而后邊的xxxxxx則根據(jù)每一個(gè)API的不同按需設(shè)計(jì),在apiv1.py中我們通過下邊這樣的代碼創(chuàng)建了版本為1的API

from app.apis.chat.resources import ns as chat_nsapi_v1 = Blueprint('api1', __name__, url_prefix='/api/v1')api = Api(api_v1, version='1.0', title='flask backend reference project', description='flask backend reference', default='chat', doc=False)api.add_namespace(chat_ns)通過指定Blueprint的url_prefix參數(shù)為/api/v1來指定我們的api基礎(chǔ)部分為 http://domain/api/v1

而API的后半部分(xxxxxx部分)則在app.apis.chat.resources中實(shí)現(xiàn)

資源

REST規(guī)范中,認(rèn)為每一個(gè)API就是訪問一個(gè)特定的服務(wù)器資源,因此API又可以叫資源,我們這個(gè)項(xiàng)目實(shí)現(xiàn)了一個(gè)chat資源,位置為app/apis/chat/resources。我們前邊講了,由于微信公眾號(hào)后臺(tái)對(duì)于API的要求,我們不能夠設(shè)計(jì)完全滿足REST規(guī)范的API,因此,在本項(xiàng)目中,只有版本和資源這兩個(gè)在概念上滿足REST規(guī)范,具體針對(duì)資源的設(shè)計(jì)并不滿足該規(guī)范,讀者可以再閱讀REST規(guī)范去學(xué)習(xí)更多的REST API知識(shí)。

我們希望微信公眾號(hào)后臺(tái)通過http://domain/api/v1/chat/message 來跟Flask后端交互,因此在resources.py中實(shí)現(xiàn)了下邊這個(gè)MessageResourceHandler,通過ns.route指定了這個(gè)資源的位置為/message,而這個(gè)資源的處理函數(shù)為MessageResourceHandler,繼承自flask_restx的Resource類。

ns = Namespace('chat', description='provide chat functionalities')@ns.route('/message', strict_slashes=False)class MessageResourceHandler(Resource):strict_slashes設(shè)置為False是告訴Flask應(yīng)用針對(duì) /message 和 /message/ 都要使用這個(gè)類來處理,而這個(gè)值如果為True的話,/message 和 /message/ 要分別處理。

總結(jié)

利用 flask_restx 來做REST API開發(fā)的時(shí)候,一個(gè)API會(huì)由三個(gè)部分組成:

微信公眾號(hào)對(duì)接

通過上邊一節(jié)的內(nèi)容,我們學(xué)會(huì)了如何定義一個(gè)API,而API的邏輯要在 MessageResourceHandler中實(shí)現(xiàn),我們的目標(biāo)是跟微信公眾號(hào)對(duì)接,因此我們的API的實(shí)現(xiàn)邏輯要滿足微信公眾號(hào)的要求,要參考微信公眾號(hào)關(guān)于API的文檔,可以在下邊這個(gè)鏈接找到。本項(xiàng)目需要掌握的微信API調(diào)用方法,都可以通過在下邊你這個(gè)頁面學(xué)會(huì),事實(shí)上,我們這個(gè)項(xiàng)目中用到的微信消息處理和回復(fù)邏輯基本上就是拷貝了示例代碼。

https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html

MessageResourceHandler的Get方法

想要把自定義的API綁定到微信公眾號(hào)后臺(tái),為了安全,微信公眾號(hào)需要對(duì)我們的API進(jìn)行認(rèn)證,也就是說,微信公眾號(hào)綁定一個(gè)API的時(shí)候要驗(yàn)證這個(gè)API是不是我們自己的,而認(rèn)證的方法是通過調(diào)用API的Get方法,然后給這個(gè)方法傳送一個(gè)秘鑰,在Get方法中對(duì)秘鑰進(jìn)行解析比對(duì),如果通過則返回特定字符串,如果不通過則什么都不返回。

我們?cè)贛essageResourceHandler中實(shí)現(xiàn)了get類方法,并將微信的秘鑰認(rèn)證邏輯進(jìn)行了實(shí)現(xiàn),有了這個(gè)方法以后,就可以在微信公眾號(hào)的后臺(tái)將http://domain/api/v1/chat/message綁定到賬號(hào)。

MessageResourceHandler的Post方法

當(dāng)API綁定成功以后,微信公眾號(hào)每次收到訂閱用戶發(fā)來的消息以后,會(huì)自動(dòng)調(diào)用綁定API(http://domain/api/v1/chat/message)的Post方法。對(duì)應(yīng)的,我們?cè)贛essageResourceHandler中實(shí)現(xiàn)了post類方法,并將收到的消息以xml格式的方式打包傳入post類方法,我們需要做的就很簡(jiǎn)單了,通過解析收到的信息,然后利用這些信息去搜索前邊已經(jīng)實(shí)現(xiàn)的內(nèi)存數(shù)據(jù)緩存,然后在組合出需要回復(fù)給用戶的消息,通過post方法的return來返回出去。

日志記錄

世界上不存在沒有bug的軟件,一個(gè)運(yùn)行在服務(wù)器上的Web應(yīng)用,如果出問題了,是需要一些手段能夠記錄下出問題時(shí)候的一些信息的,這些信息能夠輔助我們解決bug,改善產(chǎn)品功能,而Web應(yīng)用的日志就是幫我們記錄這些信息的。

Flask內(nèi)部幫忙實(shí)現(xiàn)了日志記錄器,通過Flask的全部對(duì)象current_app就可以訪問到這個(gè)日志記錄器,然后使用和Python內(nèi)置日期記錄器logging模塊一樣的方法就可以實(shí)現(xiàn)日志記錄,例如在MessageResourceHandler中的post類方法中,我們通過下邊這樣的日志記錄器調(diào)用可以記錄當(dāng)前消息是由哪個(gè)用戶發(fā)過來的,消息的內(nèi)容是什么。

current_app.logger.info("received {} from: {}".format(recMsg.Content, fromUser))而日志記錄的位置,我們?cè)谂渲谜鹿?jié)已經(jīng)講過,可以通過在config.py文件中進(jìn)行配置,在本項(xiàng)目中,我們指定開發(fā)環(huán)境的日志會(huì)打印到標(biāo)準(zhǔn)輸出,而在生產(chǎn)環(huán)境會(huì)記錄到:/var/log/pythonlibrary_api_log.log中

實(shí)現(xiàn)結(jié)果

在本篇文章中,我們對(duì)如何使用Flask搭建Web后端進(jìn)行了講解,并針對(duì)我們項(xiàng)目的關(guān)鍵代碼進(jìn)行了說明,我們建議讀者下載項(xiàng)目源碼,嘗試運(yùn)行并閱讀源碼,以更好的掌握這些知識(shí),本項(xiàng)目的代碼可以從GitHub倉庫:https://github.com/pythonlibrary/flask-wechat-backend 中獲取,最終部署完成,以及從微信公眾號(hào)中將我們自己的后臺(tái)連接成功以后,公眾號(hào)就可以處理用戶發(fā)來的消息了。









關(guān)鍵詞:公眾,后臺(tái),系統(tǒng)

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉