Python+tkinterで回線速度チェックプログラム
件名の内容をつくることがあった時のメモ。
ネットワーク回線Download速度測定
よく見かけるサイトのまねごとである。ここでは、1Mbyte、5Mbyte、10Mbyte、30Mbyte、100Mbyteのファイルを無料のStorageサービスサイトに格納し、そのサイトからのダウンロー時間や速度を測定・表示・ファイル化(CSV)する。
準備
ファイル作成
Linuxコマンドddにより作成。下記は、100Mbyteのファイル作成。
dd if=/dev/zero of=100Mbyte bs=1024 count=100*1024
URL
無料のストレージサービスサイトでは、URLが変更されることがあるようだ(セキュリティ対策と思われる)。そこで、ダウンロードするファイルのURLが変更されてても対応できるよう、別ファイル(url.txt)にURLを格納することにした。
https://himitsu.jp/9114/xxx/contents/1Mbyte
https://himitsu.jp/9123/xxx/contents/5Mbyte
https://himitsu.jp/9345/xxx/contents/10Mbyte
https://himitsu.jp/9534/xxx/contents/30Mbyte
https://himitsu.jp/980a/xxx/contents/100Mbyte
ソースコード
まずは部分的な説明。
import
import logging
import logging.handlers
from datetime import datetime
import time
import urllib.request
import tkinter
from tkinter import *
import tkinter.ttk as ttk
ログ、時間、URL、tkinterなどのライブラリインポート。
定義・リスト
w_width = 450
w_height = 400
speed_list = [1, 5, 10, 30, 100]
file_list = ['1Mbyte', '5Mbyte', '10Mbyte', '30Mbyte', '100Mbyte']
画面サイズ、速度定義のリスト。
URL取得
f = open('url.txt', 'r')
url_list = f.readlines()
f.close()
1行に1つのURLが記載されたファイルから内容を読み込み、リスト化。
表示部分作成
frm1 = ttk.Frame(frm, width=w_width, height=w_height)
frm1.Btn1 = ttk.Button(frm1, text=file_list[0], style='W.TButton', command=lambda:ok_clk(1))
frm1.Btn1.grid(row = 0, column = 0)
frm1.Btn2 = ttk.Button(frm1, text=file_list[1], style='W.TButton', command=lambda:ok_clk(2))
frm1.Btn2.grid(row = 0, column = 1)
frm1.Btn3 = ttk.Button(frm1, text=file_list[2], style='W.TButton', command=lambda:ok_clk(3))
frm1.Btn3.grid(row = 0, column = 2)
frm1.Btn4 = ttk.Button(frm1, text=file_list[3], style='W.TButton', command=lambda:ok_clk(4))
frm1.Btn4.grid(row = 0, column = 3)
frm1.Btn5 = ttk.Button(frm1, text=file_list[4], style='W.TButton', command=lambda:ok_clk(5))
frm1.Btn5.grid(row = 0, column = 4)
frm2 = ttk.Frame(frm, width=w_width, height=w_height)
frm2.label = ttk.Label(frm2, text = 'Size(Mbyte), Time(ms), Speed(Kbps)')
frm2.label.grid(row = 0, column = 0)
frm2.dummy = ttk.Label(frm2, text = ' ')
frm2.dummy.grid(row = 0, column = 1)
frm3 = ttk.Frame(frm, width=w_width, height=w_height)
frm3.prt = Text(frm3, font=("Courier New", 11), width=120, height=33)
frm3.ysc = tkinter.Scrollbar(frm3, orient=tkinter.VERTICAL, command=frm3.prt.yview)
frm3.ysc.pack(side=tkinter.RIGHT, fill="y")
frm3.prt["yscrollcommand"] = frm3.ysc.set
frm3.prt.config(state='disabled')
frm3.prt.pack()
frm1.pack()
frm2.pack()
frm3.pack()
.....
note = ttk.Notebook(self)
note.pack()
note0 = ttk.Frame(note, width=w_width, height=w_height)
note.add(note0, text=" Click Download File Size ")
cr_tab(note0)
タブ化、タブ内のフレーム化(3種類:ボタン、テキスト、結果表示部分)の実施。このあたりは、従来からの方式(例えば、「ろうとるがPythonを扱う、、(その5:tkinterでタブ)」を踏襲。
タブは必須ではなかったが、その後のプログラム拡張に備えて、あえてタブ化した。
ボタンクリック時処理
def ok_clk(arg):
start_time = time.perf_counter_ns()
urllib.request.urlretrieve(url_list[arg-1], file_list[arg-1])
end_time = time.perf_counter_ns()
elapsed_time = (end_time - start_time) / 1000000
speed = speed_list[arg-1]*8*1024*1024/elapsed_time
output = str(speed_list[arg-1]) + ', ' + str(elapsed_time) + ', ' + str(speed) + ','
log.debug(output) # output to log file
output = output + '\n'
frm3.prt.config(state='normal') # editable
frm3.prt.insert(END, output)
frm3.prt.config(state='disabled') # not editable
frm3.prt.see('end')
URLライブラリを使ってファイルをダウンロード、ダウンロード時間の計測および速度の計算、結果をログファイル(CSV)に格納および表示。
ログファイル(csv)関連
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
fh = logging.FileHandler('{:Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
log.addHandler(fh)
header = 'Size(Mbyte), Time(ms), Speed(Kbps),'
log.debug(header)
ログおよびログファイル名の定義。
メニュー
def log_tgl():
tgl.set(not tgl.get())
if tgl.get():
log.setLevel(logging.DEBUG)
fh = logging.FileHandler('{:Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
log.addHandler(fh)
header = 'Size(Mbyte), Time(ms), Speed(Kbps),'
log.debug(header)
else:
log.removeHandler(log.handlers[0])
log.setLevel(logging.INFO)
.....
menubar = Menu(self)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Exit", command=self.quit)
tgl = BooleanVar(value = TRUE)
filemenu.add_checkbutton(label="Disable Log", command=log_tgl)
master.config(menu=menubar)
ログの無効化および有効化メニューの定義。
全体
import logging
import logging.handlers
from datetime import datetime
import time
import urllib.request
import tkinter
from tkinter import *
import tkinter.ttk as ttk
w_width = 450
w_height = 400
speed_list = [1, 5, 10, 30, 100]
file_list = ['1Mbyte', '5Mbyte', '10Mbyte', '30Mbyte', '100Mbyte']
class NetworkCheck(ttk.Frame):
def __init__(self, master):
super().__init__(master)
self.create_widgets()
self.pack()
def create_widgets(self):
def cr_tab(frm):
def ok_clk(arg):
start_time = time.perf_counter_ns()
urllib.request.urlretrieve(url_list[arg-1], file_list[arg-1])
end_time = time.perf_counter_ns()
elapsed_time = (end_time - start_time) / 1000000
speed = speed_list[arg-1]*8*1024*1024/elapsed_time
output = str(speed_list[arg-1]) + ', ' + str(elapsed_time) + ', ' + str(speed) + ','
log.debug(output) # output to log file
output = output + '\n'
frm3.prt.config(state='normal') # editable
frm3.prt.insert(END, output)
frm3.prt.config(state='disabled') # not editable
frm3.prt.see('end')
## End of ok_clk()
## Start of cr_tab()
frm1 = ttk.Frame(frm, width=w_width, height=w_height)
frm1.Btn1 = ttk.Button(frm1, text=file_list[0], style='W.TButton', command=lambda:ok_clk(1))
frm1.Btn1.grid(row = 0, column = 0)
frm1.Btn2 = ttk.Button(frm1, text=file_list[1], style='W.TButton', command=lambda:ok_clk(2))
frm1.Btn2.grid(row = 0, column = 1)
frm1.Btn3 = ttk.Button(frm1, text=file_list[2], style='W.TButton', command=lambda:ok_clk(3))
frm1.Btn3.grid(row = 0, column = 2)
frm1.Btn4 = ttk.Button(frm1, text=file_list[3], style='W.TButton', command=lambda:ok_clk(4))
frm1.Btn4.grid(row = 0, column = 3)
frm1.Btn5 = ttk.Button(frm1, text=file_list[4], style='W.TButton', command=lambda:ok_clk(5))
frm1.Btn5.grid(row = 0, column = 4)
frm2 = ttk.Frame(frm, width=w_width, height=w_height)
frm2.label = ttk.Label(frm2, text = 'Size(Mbyte), Time(ms), Speed(Kbps)')
frm2.label.grid(row = 0, column = 0)
frm2.dummy = ttk.Label(frm2, text = ' ')
frm2.dummy.grid(row = 0, column = 1)
frm3 = ttk.Frame(frm, width=w_width, height=w_height)
frm3.prt = Text(frm3, font=("Courier New", 11), width=120, height=33)
frm3.ysc = tkinter.Scrollbar(frm3, orient=tkinter.VERTICAL, command=frm3.prt.yview)
frm3.ysc.pack(side=tkinter.RIGHT, fill="y")
frm3.prt["yscrollcommand"] = frm3.ysc.set
frm3.prt.config(state='disabled')
frm3.prt.pack()
frm1.pack()
frm2.pack()
frm3.pack()
## End of cr_tab()
def log_tgl():
tgl.set(not tgl.get())
if tgl.get():
log.setLevel(logging.DEBUG)
fh = logging.FileHandler('{:Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
log.addHandler(fh)
header = 'Size(Mbyte), Time(ms), Speed(Kbps),'
log.debug(header)
else:
log.removeHandler(log.handlers[0])
log.setLevel(logging.INFO)
## End of log_tgl()
## Start of create_widgets()
# Log
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
fh = logging.FileHandler('{:Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
log.addHandler(fh)
header = 'Size(Mbyte), Time(ms), Speed(Kbps),'
log.debug(header)
# Menu
menubar = Menu(self)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="Exit", command=self.quit)
tgl = BooleanVar(value = TRUE)
filemenu.add_checkbutton(label="Disable Log", command=log_tgl)
master.config(menu=menubar)
# Tab
note = ttk.Notebook(self)
note.pack()
note0 = ttk.Frame(note, width=w_width, height=w_height)
note.add(note0, text=" Click Download File Size ")
cr_tab(note0)
# Get URL
f = open('url.txt', 'r')
url_list = f.readlines()
#for i in url_list:
# print(i)
f.close()
## End of createwidgets()
## End of NetworkCheck()
if __name__ == '__main__':
master = Tk()
master.title("Speed Test v0.95b")
master.geometry("450x400")
# Call main part
NetworkCheck(master)
master.mainloop()
正直、python&tkinter的には、あまり美しいとは言えないプログラムである。
動作
EOF