見出し画像

PythonでWebの読み込み時間計測

はじめに

ネットワークエンジニアをしていますと、Webページの読み込みの時間を測定したいときがあります。

ネットワーク回線のレスポンスを知りたいとき、公開しているWebページのレスポンスを知りたいときなど、サービスを測定する必要が出てきます。

ブラウザには測定ツールも備わっておりますので、「F12キー > Networkタブ」から呼び出すこともできます。(図1はGoogle Chromeの場合)

画像1

図1 ブラウザのNetwork測定

しかし、100回の平均値が欲しいと思ったとき、20:00~22:00でサービスの低下が起きていないか確認したいとき、データとして出力するのは困難になるかと思います。

世の中にはそのような有料ツールもあるかと思いますが、簡易的でよいので無料で出力できないかと思いましたので、作成することにしました。

例:HttpWatchの有料版
  無料版は出力に対応しておりませんでした。


※Webスクレイピングに該当しますので、本コードでアクセスする際は、各ページの規約等をご確認していただければと思います。


コードの紹介

それぞれをコピーしてご利用いただければと思います。
注意点としましては、seleniumのインストールが必要となります。(インストール方法は以前の記事をご参照ください)

毎度おなじみ、動画もございますのでイメージをお伝えできればと思います。

Python_Info.py

#-------------------基本情報--------------------

#chrome driver
DriverDir = r"C:\Users\■■■\デスクトップ\python\driver\chromedriver.exe"

#デスクトップ指定
DeskTopDir = r"C:\Users\■■■\デスクトップ"

http_response.py

# -*- coding: utf-8 -*-
#-----------------------------------

#基本情報
import Python_Info

#webアクセス
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from webdriver_manager.chrome import ChromeDriverManager

#時間
import time
import datetime

 #json import json

#OS
import subprocess

#デバッグ用
import pprint

#-----------------------------------

accsess_url = [
   "https://www.yahoo.co.jp",
   "https://note.com/",
   "https://qiita.com/"
   ]

proxy = [
   "http://10.0.0.1:8080",
   "http://10.0.0.2:8080"
   ]

#-----------------------------------


###################################
#
#関数
#  指定のファイルへ書き込み
#  メモ帳で開く
#
###################################

def file_write(writeFilePath, str):
   
   #書き込み
   with open(writeFilePath, 'a') as f:
       f.writelines(str)


###################################
#
#関数
#  "message"というプロパティを抽出
#
###################################

def process_browser_log_entry(entry):
   
   #messageのmessageを抽出
   response = json.loads(entry['message'])['message']
   
   #戻り値
   return response


#######################
#
#メイン関数
#  Webサイトの読み込みURLを取得
#  読み込み終了 - 開始時間でレスポンス測定
#
#######################

def main():
   
   #日付取得
   tm = datetime.datetime.now().strftime('%m%d_%H%M')
   
   #ログ
   logTxt = ''

   #セット回数
   for i in range(100):
       
       #各proxyを利用
       for p in proxy:
           
           #各URLへアクセス
           for u in accsess_url:
               
               #capabilityオプションを指定
               caps = DesiredCapabilities.CHROME
               caps["goog:loggingPrefs"] = {"performance": "ALL"}
               
               #WebDriverのオプション指定
               options = webdriver.ChromeOptions()
               options.add_argument('--ignore-certificate-erroes') #証明書エラー回避
               options.add_argument('--incognito') #シークレットモードの設定付与
               #options.add_argument('--proxy-server=' + p) #プロキシ設定
               
               #ブラウザ立ち上げ
               driver = webdriver.Chrome(Python_Info.DriverDir, options = options, desired_capabilities = caps)
               driver.implicitly_wait(2)
               
               #URLアクセス
               driver.get(u)
               print('\nURL = ' + u)
               time.sleep(3)

               #JSONのフォーマット
               netLog = driver.get_log("performance")
               
               #JSONのperformanceを抽出
               events = [process_browser_log_entry(entry) for entry in netLog]

               #"method"名にNetwork.responseReceived含むものを抽出
               events = [event for event in events if 'Network.respons' in event['method']]

               #各performanceからタイムスタンプとURLを抽出
               detected_url = []
               timestamp_url = []
               for item in events:
                   if "response" in item["params"]:
                       if "url" in item["params"]["response"]:

                           #詳細のアクセスURL
                           detected_url.append(item["params"]["response"]["url"])

                           #timestamp
                           timestamp_url.append(item["params"]["timestamp"])


               #詳細のアクセスURL数
               n = len(detected_url)

               #アクセストータル時間
               totaltime = float(timestamp_url[n - 1]) - float(timestamp_url[0])
               totaltime = round(totaltime, 2) #小数点第2位

               #表示
               print('records:', n)
               print('start time:', timestamp_url[0])
               print('end time:', timestamp_url[n - 1])
               print('total time:', totaltime, '\n')

               #ログ作成
               logTxt = logTxt + '\n' + str(totaltime) + '\n' #レスポンスタイム

               #書き込み
               file_write(Python_Info.DeskTopDir + '\\web_response' + tm + '.log', logTxt)

               #ブラウザ閉じる
               driver.quit()


   #メモ帳で開く
   subprocess.Popen('C:/Windows/notepad.exe ' + Python_Info.DeskTopDir + '\\web_response' + tm + '.log', logTxt)


#おまじない
if __name__ == "__main__":
   main()


本コードは下記の資料をもとに作成しております。

Selenium Webdriver ページの読み込み時間の計測
https://qiita.com/nd-02110114/items/0a078973494f19a0b27f



コードの仕組み

今回は複雑なので、1行1行のコードの解説を省略させていただきます。

まず、Networkのパフォーマンスログはどのように取得できるかといいますと、次のコードとなります。
JSON形式となりますので、pprintで出力されると見やすいかと思います。

#JSONのフォーマット
netLog = driver.get_log("performance")

#中身の確認
pprint.pprint("netLog")


ただし、情報が膨大となりますので、絞っていかなければなりません。
そこに該当するコードは次の通りです。

#######################
#
#関数
#  "message"というプロパティを抽出
#
#######################

def process_browser_log_entry(entry):
   
   #messageのmessageを抽出
   response = json.loads(entry['message'])['message']
   
   #戻り値
   return response





#JSONのperformance内のeventを抽出
events = [process_browser_log_entry(entry) for entry in netLog]


#"method"名にNetwork.responseReceived含むものを抽出
events = [event for event in events if 'Network.respons' in event['method']]


#各performanceからタイムスタンプとURLを抽出
detected_url = []
timestamp_url = []
for item in events:
   if "response" in item["params"]:
       if "url" in item["params"]["response"]:

           #詳細のアクセスURL
           detected_url.append(item["params"]["response"]["url"])

           #timestamp
           timestamp_url.append(item["params"]["timestamp"])


JSONは階層となりますので、item["params"]["response"]["url"]のような抽出方法となります。

==================
※JSON形式のイメージ
==================
'method' : 'Network.responseReceived' ,
'params' : {'frameid' : 'BDA7' ,
                 'loderid' : 'C188' ,
                 'requestid' : '9878.6' ,
                 'response' : {'connectionid' : '67' ,
                                     -省略-
                                     'timing' : {} ,
                                     'url' : 'https://google.com' }
                 'timestamp' : '703617.654937' ,
                 'type' : 'Script' } }


次に、ほかのPythonファイルを呼び出す試みを行いました。
この利点としましては、コードを公開する際に誤ってID、パスワードを流出しないようにすることにあります。

画像2

図2 ディレクトリ内のPythonファイル

http_response.py


#基本情報
import Python_Info

#ブラウザ立ち上げ
driver = webdriver.Chrome(Python_Info.DriverDir, options = options, desired_capabilities = caps)

#書き込み
file_write(Python_Info.DeskTopDir + '\\web_response' + tm + '.log', logTxt)

Python_Info.py

#chrome driver
DriverDir = r"C:\Users\■■■\デスクトップ\python\driver\chromedriver.exe"

#デスクトップ指定
DeskTopDir = r"C:\Users\■■■\デスクトップ"

UserName = "しゃけしゃけ"
PassWord = "■■■"


import Python_Info と記述をいただければ、ほかのライブラリと同様にご利用いただけます。
呼び出し方は、Python_Info.DriverDirのように「ファイル名+ドット+変数名」で参照可能です。



最後に

本コードを利用する方は、ぜひSNS等でご紹介いただければと思います。

学術論文には、無料で公開されているものが多くあり、どれだけほかの論文の参考にされているかの指標がございます。(参考文献に書かれた回数が多いほど、優れた研究をされていると評価されます。)

無料で公開されているプログラムコードにも当てはまることだと思いますので、どれだけ拡散されたがが見えると嬉しいです。


また、1行1行の解説も公開する予定になりますので、気になる方がいましたら来てください。

サポートしてくださるお気持ちだけで嬉しいです。