Flask速成專案:Flask實現計算機資源的實時監控
很多人都說使用Python開發WEB應用非常方便,那麼對於WEB新手來說,到底有多方便呢?本文即將展示給你Python的魔法。 本文將通過一個例項:Flask實現計算機資源的實時監控,迅速帶你入門Flask開發。 先說一下我的水平,博主的專業並不是做WEB開發的,對於WEB方面,只會寫爬蟲,因此,只能看懂html,略看得懂css與js,我估計有很多像我一樣的小夥伴,因此,如果你的WEB掌握的水平在我之上或與我相當,那麼,這篇文章將是你迅速入門Flask的終極教程。
先放上一張成果圖: 訪問,瀏覽器能夠實時顯示我的電腦的兩個CPU的使用情況,這裡特地採用兩種顯示方式,方便大家學習程式碼。
flask介紹
Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It’s BSD licensed! 搞科研或者搞技術,還是直接看英文吧,英文是你走向NB的基礎。
flask安裝
可以參考我之前的文章:
另外,需要安裝psutil
,flask_socketio
包,可直接使用pip安裝
構建flask專案結構
在你的目錄下新建如下的目錄與檔案:
[email protected]:~/Desktop/projects/CPU_memory$ tree
.
|-- app.py
`-- templates
`-- index.html
1 directory, 2 files
非常形象的解釋下flask完成的任務 *** 瀏覽器向伺服器傳送請求,伺服器將html原始碼傳送給瀏覽器,瀏覽器將html解析成視覺化的東西展示給使用者。也就是說,使用者接收到的總是一個html檔案,那flask在整個過程中完成了什麼任務呢? 請把Flask想象成一個火腿腸加工廠*,將肉輸送給火腿腸加工廠,火腿腸加工廠生產出火腿腸。同樣,將使用者請求,例如訪問https://xujh.top這一請求傳送給flask,flask能夠生產出html。 將請求傳送給flask
對於上述專案結構的構成,app.py中實現了路由及啟動功能,templates資料夾中是模板檔案,(這裡插一句:我曾經看到很多人,在讀某個用flask做的WEB專案的原始碼,一開啟templates資料夾中,發現了很多css,js,html檔案,一開啟這些檔案,發現幾百上前行,一下子頭都大了,立馬放棄了讀程式碼,哈哈哈哈),其實,對於像我一樣專業不是做前端的小夥伴,完全可以不用擔心,這些檔案其實可以一行都不寫,例如可以用Bootstrap框架來做前端,使用Bootstrap要寫程式碼?兄弟,你不會用視覺化編輯工具嘛!!! 等以後我們做大專案,我們主要寫的也就是除了templates資料夾中以外的檔案。前端不會別擔心,我也不會。
對於這篇文章所要實現的目標,我們做一個小結:
- 執行app.py,計算機啟動flask自帶的伺服器,開始允許WEB訪問
- 使用者使用瀏覽器訪問網址
- flask接受到使用者的請求後,app.py進行邏輯上的處理,將index.html傳送給瀏覽器。
原始碼分析
原始碼的分析在註釋中,大家一定能看懂!
# -*- coding:utf-8 -*-
'''
CPU_and_MEM_Monitor
思路:後端後臺執行緒一旦產生資料,即刻推送至前端。
好處:不需要前端ajax定時查詢,節省伺服器資源。
'''
import psutil #這個庫可以用來獲取系統的資源資料,詳細可以看文件
import time
from threading import Lock
from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit
# Set this variable to "threading", "eventlet" or "gevent" to test the
# different async modes, or leave it set to None for the application to choose
# the best option based on installed packages.
async_mode = None
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode=async_mode)
thread = None
thread_lock = Lock()
# 後臺執行緒 產生資料,即刻推送至前端
def background_thread():
count = 0
while True:
socketio.sleep(2)
count += 1
t = time.strftime('%M:%S', time.localtime()) # 獲取系統時間(只取分:秒)
cpus = psutil.cpu_percent(interval=None, percpu=True) # 獲取系統cpu使用率 non-blocking
socketio.emit('server_response',
{'data': [t] + list(cpus)[0:4], 'count': count},
namespace='/test') # 注意:這裡不需要客戶端連線的上下文,預設 broadcast = True !!!!!!!
print [t] +list(cpus)[0:4]
print 100*'*'
# 當用戶訪問'/'時,執行index()函式。這也是python裝飾器的用法。
@app.route('/')
def index():
return render_template('index.html', async_mode=socketio.async_mode)
# 每次執行render_template函式時,渲染器都會將index.html的變數值用其實際值替代。
# 與前端建立 socket 連線後,啟動後臺執行緒
@socketio.on('connect', namespace='/test')
def test_connect():
global thread
with thread_lock:
if thread is None:
thread = socketio.start_background_task(target=background_thread)
if __name__ == '__main__':
socketio.run(app, debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CPU_and_MEM_Monitor</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>
<!-- ECharts 3 引入 -->
<script src="http://echarts.baidu.com/dist/echarts.min.js"></script>
</head>
<body>
<!--為ECharts準備一個具備大小(寬高)的Dom-->
<div id="CPU1" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
<div id="CPU2" style="height:500px;border:1px solid #ccc;padding:10px;"></div>
<script type="text/javascript">
//--- 折柱 ---
// 3個全域性變數:time、cpu1、cpu2
var time = ["","","","","","","","","",""],
cpu1 = [0,0,0,0,0,0,0,0,0,0],
cpu2 = [0,0,0,0,0,0,0,0,0,0]
//第一張echarts圖初始化
var CPU1 = echarts.init(document.getElementById('CPU1'));
CPU1.setOption({
title: {
text: 'CPU1'
},
tooltip: {},
legend: {
data:['cpu1']
},
xAxis: {
data: []
},
yAxis: {},
series: [{
name: 'cpu1',
type: 'line',
data: []
}]
});
//準備好的 callback 函式
var update_CPU1 = function (res) { //res是json格式的response物件
// 隱藏載入動畫
CPU1.hideLoading();
// 準備資料
time.push(res.data[0]);
cpu1.push(parseFloat(res.data[1]));
if (time.length >= 10){
time.shift();
cpu1.shift();
}
// 填入資料
CPU1.setOption({
xAxis: {
data: time
},
series: [{
name: 'cpu1', // 根據名字對應到相應的系列
data: cpu1
}]
});
};
//第二張echarts圖初始化
var CPU2 = echarts.init(document.getElementById('CPU2'));
CPU2.setOption({
title: {
text: 'CPU2'
},
tooltip: {},
legend: {
data:['cpu2']
},
toolbox: {
show : true,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
magicType : {show: true, type: ['line', 'bar', 'stack', 'tiled']},
restore : {show: true},
saveAsImage : {show: true}
}
},
calculable : true,
xAxis: {
data: []
},
yAxis: {},
series: [{
name: 'cpu2',
type: 'line',
smooth:true,
itemStyle: {normal: {areaStyle: {type: 'default'}}},
data: []
}]
});
//準備好的 callback 函式
var update_CPU2 = function (res) { //res是json格式的response物件
// 隱藏載入動畫
CPU2.hideLoading();
// 準備資料
time.push(res.data[0]);
cpu2.push(parseFloat(res.data[2]));
if (time.length >= 10){
time.shift();
cpu2.shift();
}
// 填入資料
CPU2.setOption({
xAxis: {
data: time
},
series: [{
name: 'cpu2', // 根據名字對應到相應的系列
data: cpu2
}]
});
};
// 首次顯示載入動畫
CPU1.showLoading();
CPU2.showLoading();
// 建立socket連線,等待伺服器“推送”資料,用回撥函式更新圖表
$(document).ready(function() {
namespace = '/test';
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);
socket.on('server_response', function(res) {
update_CPU1(res);
update_CPU2(res);
});
});
</script>
</body>
</html>