【Python3】インターネット回線速度を定期計測してCSVに保存

##インターネットの回線速度の時系列データをCSVで出したいね
インターネットの回線速度が、一日、あるいは週の中でどう変化しているのかを可視化したいと思いました。いろいろとツールはあると思いますが、書き慣れてるPythonでいいライブラリーがあったらそれで書きたいなと思ったら、やっぱりありました。便利なもんですね。先人たちが定期実行するスクリプトも公開してくださっているので、丸コピして少し手を加えます。

#注意　1分おきに高頻度で叩くこの方法だとIPをブロックされる可能性があります。今調べてますが、どうもやらかしたっぽい。

###環境
macOS BigSur 11.3.1
Python3.9

```speedtest_regulary.py
import speedtest
import datetime
import time
import csv
import logging

INTERVAL_SEC = 60

def get_speed_tester():
    servers = []
    stester = speedtest.Speedtest()
    stester.get_servers(servers)
    stester.get_best_server()
    return stester

def get_timestamp():
    date = datetime.datetime.now()
    timestamp = str(date.strftime('%Y-%m-%d %H:%M:%S'))
    return timestamp

def test_speed(stester):
    down_result = str(int(stester.download()))
    up_result = str(int(stester.upload()))
    return down_result, up_result

def command_line_runner():
    stester = get_speed_tester()
    print('time,down(bps),up(bps)')
    logger = logging.getLogger('SpeedtestLogging')
    fh = logging.FileHandler('speedtestlogging.log')
    logger.addHandler(fh)
    sh = logging.StreamHandler()
    logger.addHandler(sh)

    while True:
        try:
            t1 = time.time()
            timestamp = get_timestamp()
            down_result, up_result = test_speed(stester)
            print(timestamp + ',' + down_result + ',' + up_result)
            with open('speedtest_regulary_output.csv', 'a') as f:
                writer = csv.writer(f)
                writer.writerow([timestamp, down_result, up_result])
            t2 = time.time()
            next_sleep_time = int(INTERVAL_SEC - (t2 - t1))
            time.sleep(next_sleep_time)

        except KeyboardInterrupt:
            print("Ctrl+Cで停止")
            break

        except Exception as err:
            logger.exception('Raise Exception: %s', err)

if __name__ == '__main__':
    command_line_runner()
```

なお、SSL接続のためにルート証明書の取得が必要です。

```
speedtest.ConfigRetrievalError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)>
```
↑はじめて動かした時にはこんな感じのエラーが吐かれました。
解決策は以下をterminalで実行することです。

```
/Applications/Python\ 3.9/Install\ Certificates.command
```
https://github.com/pyenv/pyenv/issues/1643
Python3.7以降ではこのおまじないが必要らしいです。同じエラーに遭遇した時には環境に合わせて同じことを試してみてください。

では書いてみたスクリプトの挙動を見てみます。
↓作成されるCSVファイル
![スクリーンショット 2021-05-10 2.15.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158553/59e5a983-7915-aeb3-8638-c342542587d6.png)


loggingでエラーをキャッチして保存するようにしました。でも、speedtestライブラリの方ですでにかなりしっかり処理しちゃってますね。
https://github.com/sivel/speedtest-cli/blob/master/speedtest.py
実行しながらwifiを落としてみたのですが、その場合にはアップロード/ダウンロードとも0bpsというデータが作られ、上のようになりました。loggingには何も追加されていませんでした。ネットワークのエラーは全く取れないかもしれません。それでもいいのかも。あくまでスピードテストをするためのものですね。

数字の単位ですが、1024で割ってやればkbpsに、さらに1024で割ればmbpsになります。

###追記
いや冷静に考えてPythonをtime.sleep()で常時動かすのは違うでしょ。
cronで定期実行します。

```speedtest_regulary_cron.py
import speedtest
import datetime
import csv
import logging


def get_speed_tester():
    servers = []
    stester = speedtest.Speedtest()
    stester.get_servers(servers)
    stester.get_best_server()
    return stester

def get_timestamp():
    date = datetime.datetime.now()
    timestamp = str(date.strftime('%Y-%m-%d %H:%M:%S'))
    return timestamp

def test_speed(stester):
    down_result = str(int(stester.download()))
    up_result = str(int(stester.upload()))
    return down_result, up_result

def command_line_runner():
    stester = get_speed_tester()
    logger = logging.getLogger('SpeedtestLogging')
    fh = logging.FileHandler('speedtestlogging.log')
    logger.addHandler(fh)
    sh = logging.StreamHandler()
    logger.addHandler(sh)


    try:
        timestamp = get_timestamp()
        down_result, up_result = test_speed(stester)
        # print(timestamp + ',' + down_result + ',' + up_result)
        with open('speedtest_regulary_output.csv', 'a') as f:
            writer = csv.writer(f)
            writer.writerow([timestamp, down_result, up_result])

    except Exception as err:
        logger.exception('Raise Exception: %s', err)

if __name__ == '__main__':
    command_line_runner()
```

これを1分おきに動かしましょう。
terminalで

```
$ crontab -e
```
で編集。

```/tmp/crontab.
* * * * * /Library/Frameworks/Python.framework/Versions/3.9/bin/python3 /Users/y_mohrey/Desktop/speedtest_regulary_cron.py
```

うーん、これでは、動きません。
cronはPATHまわりで罠が多いです。Pythonの本体も、実行ファイルも、絶対パスで書くのが大事なのはわかってます。。それでもまだこのスクリプトは動いてません。順次、追記していきます...。

###参考

speedtest-cliのPython API（本家）
https://github.com/sivel/speedtest-cli/wiki

スクリプトはほぼこちらからのコピペです。
https://qiita.com/yokobonbon/items/67deb3fab84b0c0954e0

SSL接続でエラーが出た際、応急処置としてはこちらで紹介されている一時的にPATHを通す方法は有効でした。
ここで書いてある方法ではterminalを閉じて再度開くと設定は元に戻っちゃいます。解決策は本文中で書いたやり方です。
https://qiita.com/tommy19970714/items/96edba36dfde468e26f3

cronは曲者
https://qiita.com/syunyo/items/69c3523a8c500b37f33f
https://tanuhack.com/cron/

speedtestの認証周りのエラー
https://community.home-assistant.io/t/issues-with-speedtest-automation/290967

speedtestの既知のバグ（cronで実行する際に出るバグらしいですが修正済みでした。）
https://github.com/home-assistant/core/issues/47673