この記事は JSL (日本システム技研) Advent Calendar 2019 の13日目の記事です。
最近、社内のWiFiが遅くなるタイミングがあるような気がしていて、とはいえどの程度遅くなっているか定量的に分からなかったため、スピードテストを定期実行するスクリプトを書いてみました。
最初にまとめ
- Speedtest CLI - Internet connection measurement for developers を使って社内WiFiの速度計測するプログラムをPythonで書いた
- CUIからスピードテスト実行できると便利
CUIからスピードテスト
まず、cron等で定期的に実行したかったためCUIでスピードテストを実行することを考えました
私のイメージではスピードテストといえば以下のように検索→実行…のようにして計測するものでした。
Linux上でネットワーク回線速度を計測する手段について整理してみた | Developers.IO) の記事などをみつつ調査したところ speedtest.net
がCLIを提供しているようでした
また、Speedtest CLIはPython packageも提供しており、
- pipでbinaryをinstallすることが可能
- brewで管理しなくても仮想環境化でspeedtestコマンドが使えそう
- Python上でimportすることもできそう
なことがわかりました
speedtest実行環境の構築
pipenvを使って環境構築しました
$ mkdir wifi_speedtest
$ cd $_
# pipenv 未インストールの場合
# brew install pipenv
# 仮想環境作成
$ pipenv --python 3.7
# パッケージのインストール
$ pipenv install speedtest-cli
# 仮想環境の有効化
$ pipenv shell
# speedtestコマンドのテスト
(.venv) $ speedtest --version
speedtest-cli 2.1.2
Python 3.7.4 (default, Oct 12 2019, 18:55:28) [Clang 11.0.0 (clang-1100.0.33.8)]
CUI上でSpeedtestを実行してみる
speedtest --list
で有志が提供している接続先サーバの一覧が取れるのでいずれかに決めて番号を控えておきます。
(.venv) $ speedtest --list | grep Tokyo
15047) OPEN Project (via 20G SINET) (Tokyo, Japan) [6.34 km]
24333) Rakuten Mobile , Inc (Tokyo, Japan) [6.34 km]
28910) fdcservers.net (Tokyo, Japan) [6.34 km]
18516) GIAM PING VIETPN.COM (Tokyo, Japan) [6.34 km]
22247) Tokyonet (Castro, Brazil) [18486.74 km]
以下のように指定すると常に指定したサーバでスピードテストを実行します。例えば、 Rakuten Mobile , Inc
提供のサーバの場合、番号は 24333
となります。
# スピードテストを実行
(.venv) $ speedtest --server 24333
Retrieving speedtest.net configuration...
Testing from XXX (xx.xx.xx.xx)...
Retrieving speedtest.net server list...
Retrieving information for the selected server...
Hosted by Rakuten Mobile , Inc (Tokyo) [6.34 km]: 200.123 ms
Testing download speed................................................................................
Download: 16.08 Mbit/s
Testing upload speed......................................................................................................
Upload: 31.96 Mbit/s
無事計測できました(クライアント情報は一部隠しています)
- Download: 16.08 Mbit/s
- Upload: 31.96 Mbit/s
ただ、これだとプログラム上で扱いづらいので --json
を付与して json 形式で結果を取得してみます
(.venv) $ speedtest --server 24333 --json
{"download": 20208058.464686207, "upload": 54426180.687909536, "ping": 48.215, "server": {"url": "http://ookla.mbspeed.net:8080/speedtest/upload.php", "lat": "35.6833", "lon": "139.6833", "name": "Tokyo", "country": "Japan", "cc": "JP", "sponsor": "Rakuten Mobile , Inc", "id": "24333", "host": "ookla.mbspeed.net:8080", "d": 6.336536019993832, "latency": 48.215}, "timestamp": "2019-12-23T07:23:16.316637Z", "bytes_sent": 68534272, "bytes_received": 25353712, "share": null, "client": {"ip": "xx.xx.xx.xx", "lat": "xx.xxxx", "lon": "xxx.xxxx", "isp": "XXX", "isprating": "3.7", "rating": "0", "ispdlavg": "0", "ispulavg": "0", "loggedin": "0", "country": "JP"}}
これをPython上で扱うことを考えます
PythonでSpeedtestを実行する
せっかくPython Packageとして提供しているので、Pythonの中でプラグラマブルにスピードテストを実行することも考えましたが、今回はCUIでの実行結果をそのまま扱うことを考えたので subprocessモジュール
でspeedtestコマンドを実行することにしました
subprocess --- サブプロセス管理 — Python 3.8.1 ドキュメント
def get_speedtest_result():
process = subprocess.run(['speedtest', '--server', '24333', '--json'], capture_output=True)
return json.loads(process.stdout)
def bit_to_mbit(bit):
"""
誤差とかは気にしない感じの作り
"""
return bit / 1024 / 1024
result = get_speedtest_result()
print(bit_to_mbit(result["download"]), bit_to_mbit(result["upload"]))
13.46394215 50.48002296
subprocess
でコマンド実行する方法はいくつかありますが、今回は公式で使用例に載っている run()
+ capture_output=True
で標準出力を取得しました
今回はSpreadSheetのAPIを叩いて記録するようにしました(詳細は割愛 以下を大いに参考にさせていただきました)。
Slackに飛ばすなり好きな方法で記録すると良いと思います。
余談ですが、Pipenvのscriptsを活用すると、cronから実行するときの仮想環境の有効化などが不要で便利でした(pipenv run経由で実行したプロセスは仮想環境化での実行と同じ扱いになる)
[scripts]
dev = 'python wifi_speedtest.py'