0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ろうとるがPythonを扱う、、(その13:回線速度checkプログラムその2)

Posted at

ろうとるがもっと頭がよくなるために

こちらの記事「ろうとるがPythonを扱う、、(その12:回線速度checkプログラム)」の続きである。少しでもスマートになろうとしたときのメモ。

すること

  • ダウンロード時の進行状況表示
  • コード簡略化

先に実行状況

実行状況のコピー.png
各サイズに相当するボタンをクリックすると、指定回数繰り返しダウンロードし、速度などを表示するとともに、CSVファイルを作成。青枠で囲った部分で示すように、ダウンロード状況(%)を表示する。

ソースコード

いつものように、ポイントとなる箇所を中心に説明。最後にコード全体を記載。

import

import logging
import logging.handlers
from datetime import datetime
import time
import urllib.request                  # ダウンロード用URLライブラリ
import tkinter
from tkinter import *
import tkinter.ttk as ttk
import threading              # スレッド
from functools import partial # 複数ボタンをまとめて定義(後述)

説明略。

定義

w_width = 750
w_height = 400

speed_list = [1, 5, 10, 30, 100]
url_list = [
    'https://www.4fgh.dr.jp/data/1MByte',
    'https://www.4fgh.dr.jp/data/5MByte',
    'https://www.4fgh.dr.jp/data/10MByte',
    'https://www.4fgh.dr.jp/data/30MByte',
    'https://www.4fgh.dr.jp/data/100MByte']
file_list = ['1Mbyte', '5Mbyte', '10Mbyte', '30Mbyte', '100Mbyte']
p_flag = 0 # for progress
  • Windowサイズの定義。
  • ダウンロードするファイルのURL(仮のもの)、サイズ定義など。
  • ダウンロード状況表示に関連するフラグ(p_flag)。

メイン

class NetworkCheck(ttk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.create_widgets()
        self.pack()
...()

## End of NetworkCheck()

if __name__ == '__main__':
    master = Tk()
    master.title("Repeat Download 2")
    master.geometry("750x400")
    # Call main part
    NetworkCheck(master)
    master.mainloop()
  • tkinterフレームワークにて、NetworkCheckというメイン関数をCall。
  • create_widgetsにて、各要素を配置。
    def create_widgets(self):
...

        ## Start of create_widgets()
        # Log
        log = logging.getLogger('Download')
        log.setLevel(logging.DEBUG)
        fh = logging.FileHandler('{:Download_Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
        log.addHandler(fh)
        header = 'Start Time, Size(Mbyte), Elapsed Time(ms), Speed(Mbps), Failure,'
        log.debug(header)
        # 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)
    ## End of createwidgets()
  • CSV化するログファイルの定義。
  • タブの定義(1つしか存在しないが)。

タブ

        def cr_tab(frm):
...

        ## Start of cr_tab()
            frm1 = ttk.Frame(frm, width=w_width, height=w_height)
            frm1.Btn = [ttk.Button(frm1, text=file_list[i], style='W.TButton', command=partial(clk_btn, i)) \
                        for i in range(5)]
            [frm1.Btn[i].grid(row = 0, column = i) for i in range(5)]

            frm1.label = ttk.Label(frm1, text=' Repetition Number ')
            frm1.label.grid(row = 0, column = 5)
            frm1.text = ttk.Entry(frm1, width = 10)
            frm1.text.grid(row = 0, column = 6)

            frm2 = ttk.Frame(frm, width=w_width, height=w_height)
            frm2.label = ttk.Label(frm2, text = 'Start Time, Size(Mbyte), Elapsed Time(ms), Speed(Mbps), Failure')
            frm2.label.grid(row = 0, column = 0)
            frm2.dummy = ttk.Label(frm2, text = '                                                    	  ')
            frm2.dummy.grid(row = 0, column = 1)
            frm2.progress = ttk.Label(frm2, text = '  ')
            frm2.progress.grid(row = 0, column = 2)

            frm3 = ttk.Frame(frm, width=w_width, height=w_height)
            frm3.prt = Text(frm3, font=("Courier New", 15), 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()

ボタンクリック

            ## Start of clk_btn()
            def clk_btn(size):
                th = threading.Thread(target=download, args=(size, ))
                th.start()

ダウンロード進行状況や結果をリアルタイムに表示するには、ボタンクリック時にCallされる部分をスレッド化する必要がある。これについては、こちらのサイト「tkinterで遅い処理を別スレッドに投げ画面が固まらないようにする」を参考にした。Call元にて定義された変数は、Call元に戻らないと更新されないようだ。

ダウンロード

            ## Start of download()
            def download(arg):
                num0 = frm1.text.get()
                if num0 == "":
                    num = 1
                else:
                    num = int(num0)
                for i in range(num):
                    global p_flag
                    start_datetime = datetime.now().strftime("%Y%m%d_%H%M%S")
                    start_time = time.perf_counter_ns()
                    failure = 0
                    try:
                        urllib.request.urlretrieve(url_list[arg], file_list[arg], progress)
                    except:
                        frm2.progress["text"] = 'Error'
                        failure = 1
                        time.sleep(1)
                    p_flag = 0
                    frm2.progress["text"] = 'End'
                    end_time = time.perf_counter_ns()
                    elapsed_time = (end_time - start_time) / 1000000
                    speed = speed_list[arg]*8*1024/elapsed_time
                    output = start_datetime + ', ' + str(speed_list[arg]) + ', ' + str(elapsed_time) + ', ' + str(speed) \
                        + ', ' + str(failure)
                    log.debug(output)
                    output = output + '\n'
                    frm3.prt.config(state='normal')
                    frm3.prt.insert(END, output)
                    frm3.prt.config(state='disabled')
                    frm3.prt.see('end')
                    time.sleep(1)
                    frm2.progress["text"] = ''
            ## End of download()
  • ダウンロード繰り返し数(num0)の取得(未入力時は"1"とする)。
  • ログ用の開始時刻(start_datetime)の取得。
  • 開始時間(start_time)の記録。
  • URLLib(urllib.request.urlretrieve)によるファイルダウンロード。
    • 途中経過処理行うCallback関数はprogress(後述)。
    • ダウンロードエラー時に進行状況表示を”Error”とする。
  • 終了時間(end_time)の記録。
  • ダウンロード時間(elapsed_time)および速度(speed)の計算。
  • 結果をバッファ(output)に格納、ログに記録(log.debug)、画面表示(frm3.prt.insert)。

進行状況表示

            ## Start of progress()
            def progress(block_count, block_size, total_size):
                global p_flag
                percent = 100.0 * block_count * block_size / total_size
                about = round(percent)
                curr = about % 5
                if curr == 0 and p_flag == 0:
                    frm2.progress["text"] = str(about)
                    p_flag = 1
                if curr >= 1:
                    p_flag = 0
            ## End of progress()

こちらの記事「Pythonでファイルをダウンロード&プログレスバーを表示させる」を参考に作成。

  • 進行状況を%(percent)で取得。
  • 5%で表示(frm2.progressのText置き換え)するため、制御用フラグ(p_flag)を設ける。
    • 表示したタイミングで、p_flagを1にセット。
    • 進行状況(percent)が5で割り切れないときやダウンロード終了時に、p_flagを0にセット(リセット)。

全体

import logging
import logging.handlers
from datetime import datetime
import time
import urllib.request
import tkinter
from tkinter import *
import tkinter.ttk as ttk
import threading
from functools import partial

w_width = 750
w_height = 400

speed_list = [1, 5, 10, 30, 100]
url_list = [
    'https://www.4fgh.dr.jp/data/1MByte',
    'https://www.4fgh.dr.jp/data/5MByte',
    'https://www.4fgh.dr.jp/data/10MByte',
    'https://www.4fgh.dr.jp/data/30MByte',
    'https://www.4fgh.dr.jp/data/100MByte']
file_list = ['1Mbyte', '5Mbyte', '10Mbyte', '30Mbyte', '100Mbyte']
p_flag = 0 # for progress

class NetworkCheck(ttk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.create_widgets()
        self.pack()

    def create_widgets(self):
        def cr_tab(frm):
            ## Start of progress()
            def progress(block_count, block_size, total_size):
                global p_flag
                percent = 100.0 * block_count * block_size / total_size
                about = round(percent)
                curr = about % 5
                if curr == 0 and p_flag == 0:
                    frm2.progress["text"] = str(about)
                    p_flag = 1
                if curr >= 1:
                    p_flag = 0
            ## End of progress()

            ## Start of download()
            def download(arg):
                num0 = frm1.text.get()
                if num0 == "":
                    num = 1
                else:
                    num = int(num0)
                for i in range(num):
                    global p_flag
                    start_datetime = datetime.now().strftime("%Y%m%d_%H%M%S")
                    start_time = time.perf_counter_ns()
                    failure = 0
                    try:
                        urllib.request.urlretrieve(url_list[arg], file_list[arg], progress)
                    except:
                        frm2.progress["text"] = 'Error'
                        failure = 1
                        time.sleep(1)
                    p_flag = 0
                    frm2.progress["text"] = 'End'
                    end_time = time.perf_counter_ns()
                    elapsed_time = (end_time - start_time) / 1000000
                    speed = speed_list[arg]*8*1024/elapsed_time
                    output = start_datetime + ', ' + str(speed_list[arg]) + ', ' + str(elapsed_time) + ', ' + str(speed) \
                        + ', ' + str(failure)
                    log.debug(output)
                    output = output + '\n'
                    frm3.prt.config(state='normal')
                    frm3.prt.insert(END, output)
                    frm3.prt.config(state='disabled')
                    frm3.prt.see('end')
                    time.sleep(1)
                    frm2.progress["text"] = ''
            ## End of download()

            ## Start of clk_btn()
            # https://www.haya-programming.com/entry/2019/01/20/012926
            def clk_btn(size):
                th = threading.Thread(target=download, args=(size, ))
                th.start()

        ## Start of cr_tab()
            frm1 = ttk.Frame(frm, width=w_width, height=w_height)
            # list     https://qiita.com/omossan7182t/items/a3ffb3788667de937c59
            # partial  https://qiita.com/yuzukaki/items/9dd3a4481e1f6e6fa0a8
            frm1.Btn = [ttk.Button(frm1, text=file_list[i], style='W.TButton', command=partial(clk_btn, i)) \
                        for i in range(5)]
            [frm1.Btn[i].grid(row = 0, column = i) for i in range(5)]

            frm1.label = ttk.Label(frm1, text=' Repetition Number ')
            frm1.label.grid(row = 0, column = 5)
            frm1.text = ttk.Entry(frm1, width = 10)
            frm1.text.grid(row = 0, column = 6)

            frm2 = ttk.Frame(frm, width=w_width, height=w_height)
            frm2.label = ttk.Label(frm2, text = 'Start Time, Size(Mbyte), Elapsed Time(ms), Speed(Mbps), Failure')
            frm2.label.grid(row = 0, column = 0)
            frm2.dummy = ttk.Label(frm2, text = '                                                    	  ')
            frm2.dummy.grid(row = 0, column = 1)
            frm2.progress = ttk.Label(frm2, text = '  ')
            frm2.progress.grid(row = 0, column = 2)

            frm3 = ttk.Frame(frm, width=w_width, height=w_height)
            frm3.prt = Text(frm3, font=("Courier New", 15), 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()

        ## Start of create_widgets()
        # Log
        log = logging.getLogger('Download')
        log.setLevel(logging.DEBUG)
        fh = logging.FileHandler('{:Download_Log-%Y%m%d-%H%M%S}.csv'.format(datetime.now()))
        log.addHandler(fh)
        header = 'Start Time, Size(Mbyte), Elapsed Time(ms), Speed(Mbps), Failure,'
        log.debug(header)
        # 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)
    ## End of createwidgets()
## End of NetworkCheck()

if __name__ == '__main__':
    master = Tk()
    master.title("Repeat Download 2")
    master.geometry("750x400")
    # Call main part
    NetworkCheck(master)
    master.mainloop()

EOF

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?