PageSpeed Insights API を使って Python にページの平均点を計測させる

5 min読了の目安(約4500字TECH技術記事

はじめに

今所属しているプロダクトでは、検索結果の上位表示やサイト閲覧時のストレス軽減を目的に PageSpeed Insights (以下、PSI )を指標にページスピードの改善を測っています。

改善結果を Before/After で計測していくわけですが、PSI の点数は計測するタイミングによっては余裕で10〜30点のブレが出たりします。

そういうわけで、僕のチームでは1ページ1計測ではなく、数回計測して

  • 平均点
  • 測定回数(15回以上)
  • ブレが大きい場合は最低点・最高点

を記載する方式でやっていくことにしました。

が、これだと計測したいページが増えるほどに、 分析 ボタンをカチっとやって待つ時間が当然とてもつらいものになります。
今回は API を使ってこれを効率化してみました。

対象読者像

  • API を使ってデータを取得したいプログラミング初学者〜エンジニア1年目

完成品

kotahashihama/psi-score-collector
https://github.com/kotahashihama/psi-score-collector

API キーの取得

PageSpeed Insights API からデータを取得するには、アクセス時にパラメーターとして添える形で API キーが必要になります。

以下のページで取得できます。

PageSpeed Insights API を使ってみる  |  Google Developers
https://developers.google.com/speed/docs/insights/v5/get-started

プロジェクトコード内に API キーをそのままで置いておくのはセキュリティ上よくないので、ライブラリの python-dotenv を使い .env で環境変数として管理するようにしました。

ターミナル
pip install python-dotenv
config.py
from dotenv import load_dotenv
load_dotenv()

import os
API_KEY = os.getenv('API_KEY')
.env
API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

設定項目を用意

設定した測定回数ごとに順々に測定させていきたいので、必要なのは以下の項目です。

main.py
# 測定回数
measurement_count = 3;

# 測定対象 URL
url_list = [
  'https://www.google.com/',
  'https://www.yahoo.co.jp/',
  'https://www.bing.com/'
]

設定内容は処理から切り離した形にするのが本来よさそうなんですが、今回はこれでいきます。

メイン処理の記述

URL ごとに

  • ステップ数
  • モバイルの点数
  • パソコンの点数

を出力させていき、最後に測定完了のメッセージを表示させます。

main.py
print('\n'.join(map(str, url_list)))
print(f'を測定中...({measurement_count}回計測)')

for i, url in enumerate(url_list):
  print(f'\n({i + 1}/{len(url_list)}) {url}')

  measure('mobile')
  measure('desktop')

  print('\n' + '=' * 60)

print('\n測定完了!')

点数を取得させよう

SPI の API にアクセスする URL とパラメーターを用意しておきます。

main.py
api_url = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed'
api_key = config.API_KEY

payload = { 'key': api_key }

上のほうで作った config.py では、.env から読み込んだ環境変数を持たせています。

main.py
import config

config を読み込み、api_key へ値をセットしておきましょう。

点数を取ってくる処理

まず、以下がコードの全貌です。

main.py
def measure(device):
  device_name = {
    'mobile': 'モバイル',
    'desktop': 'パソコン'
  }

  print(f'[ {device_name[device]} ]')

  payload['strategy'] = device
  url_name = api_url + "?url=" + url

  scores = []

  for i in range(measurement_count):
    result = requests.get(url_name, params = payload)
    result_json = result.json()
    result_score = result_json['lighthouseResult']['categories']['performance']['score']
    displayed_score = math.floor(result_score * 100)

    scores.append(displayed_score)
    print(displayed_score, end=' ')

  score_average_raw = numpy.average(scores)
  score_average = Decimal(str(score_average_raw)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)
  score_max = numpy.amax(scores)
  score_min = numpy.amin(scores)
  print(f'\n平均 {score_average} 点(最低 {score_min} 点、最高 {score_max} 点)')

この処理の中では大きく2種類のライブラリが使われていて

  • API にアクセス
  • 結果を計算

しています。

(今回は触れませんが、Python ライブラリは Poetry 等で依存関係管理をすると、チームメンバーにも共有しやすいかと思います)

API にアクセスするライブラリ

requests という Python ライブラリを使います。

ターミナル
pip install requests
main.py
import requests
main.py
result = requests.get(url_name, params = payload)
result_json = result.json()
result_score = result_json['lighthouseResult']['categories']['performance']['score']

get() で API にアクセスし、json() で結果を JSON 化し、点数が格納されている score までをたどっています。

結果を計算するライブラリ

  • math
  • numpy
  • decimal

という計算系の Python ライブラリを使います。
このうち、numpy は標準で入っていないため、pip でインストールします。

ターミナル
pip install numpy
main.py
import numpy

decimal では Decimal オブジェクトと四捨五入のための定数 ROUND_HALF_UP だけを使うため、インポート時にこの形で読み込みます。

main.py
from decimal import Decimal, ROUND_HALF_UP
main.py
score_average_raw = numpy.average(scores)
score_average = Decimal(str(score_average_raw)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)
score_max = numpy.amax(scores)
score_min = numpy.amin(scores)
  • numpy では点数からそれぞれ平均点の計算、最高点、最低点のみを取得
  • decimalDecimal オブジェクトでは平均値を四捨五入して小数点第一位までを表示

しています。

使ってみる

実行したら、あとは放置で点数を収集してくれます。
終了を知らせるのに terminal-notifier とかを使うとより便利かもしれません。

ターミナル
py main.py

スクリーンショット 2020-07-18 午後8.26.48.png

こんな感じで計測結果が溜まっていきます。

まとめ

データを取得〜加工は、めちゃめちゃファンダメンタルな部分なので業務のいろんなところで活かせそうですね。
エンジニアたるもの、息を吸って吐くようにこういったツールを作れるようになりたい所存です。