Playwrightを使ったら自動化が捗った話
みなさんは業務のちょっとしたブラウザ操作を自動化したいと思ったことはありませんか?
私の場合、デプロイ時にブラウザを操作してあれこれしなければならない手順があり、それを何とかしたいなあと思って自動化に着手し始めました。
ブラウザ操作の自動化といえば、Seleniumが有名ですよね。
私も最初はSeleniumを使って自動化に取り組んでいました。
しかし実際にSeleniumで自動化に取り組んでみると
- 意図した通りに操作させるコードを書くのが難しい
- 動作がなかなか安定しない(しばしばエラー落ちする)
- 公式のドキュメントが読みづらく、欲しい情報を集めづらい
などの問題に突き当たってしまい開発に苦戦していました。
(もちろん私にSeleniumの知見が無かったから、というのも大きな要因としてあると思います。)
「ちょっとSeleniumは難しいな……」と感じてSelenium以外の選択肢は何か無いかと調べていたところ、Playwrightに行きつきました。
Playwrightとは?
PlaywrightはMicrosoftによって開発されたOSSのブラウザ操作自動化ツールです。
今回はPythonを使っていますが、Node.js, Java, .NETにも対応しているようです。
Playwrightの良いところ
ここからは実際にPlaywrightを使用してみて、良かった点を5つあげていきます。
1. 自動待機が優秀
まず自動待機とは何か、ということについて説明します。
例えば
「ログイン画面に遷移して、メールアドレスとパスワードを入力して、ログインボタンを押してログインする」
という操作について考えてみます。
Seleniumを使って書くと以下のような感じになるかと思います(ChatGPTに書いてもらった適当コードなので流し読みでOKです)。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
# ログイン情報
LOGIN_URL = "https://example.com/login"
EMAIL = "your_email@example.com"
PASSWORD = "your_password"
# WebDriverのセットアップ(Chromeを使用)
driver = webdriver.Chrome()
try:
# ログインページにアクセス
driver.get(LOGIN_URL)
# メールアドレス入力
email_input = driver.find_element(By.NAME, "email") # 'name' 属性が 'email' の要素を探す
email_input.send_keys(EMAIL)
# パスワード入力
password_input = driver.find_element(By.NAME, "password") # 'name' 属性が 'password' の要素を探す
password_input.send_keys(PASSWORD)
# ログインボタンをクリック
login_button = driver.find_element(By.XPATH, "//button[@type='submit']") # 'type=submit' のボタンを探す
login_button.click()
# 少し待機(ページ遷移を待つ)
time.sleep(5)
# ログイン成功の確認
if "Dashboard" in driver.title:
print("ログイン成功!")
else:
print("ログイン失敗")
finally:
# ブラウザを閉じる
driver.quit()
ありふれていて何の難しさも無いようですが、実際に動かしてみると以下のような問題が発生する場合があります。
- ログイン画面に遷移したときにメールアドレスを入力する欄が発見できず、実行に失敗する
- メールアドレスが入力可能な状態になっておらず、実行に失敗する
この問題に対処するにはSeleniumではwaitを書く必要がありました。なので、上のようなコードをそのまま使おうとすると割とコケることがありました。
「じゃあwaitを書けばいいだけじゃないの?」と思うのですがImplicit waitとExplicit wait、どちらを試してもなかなか意図した動作にならず、個人的に難しいポイントの一つでした。
一方、Playwrightではこういったwaitを書く必要がありません。
指定した要素に対して何かしらのアクションをしようとしたときに、それができるようになるまで自動待機してくれます。(できるようになるまでといっても無限に待つわけではなく、デフォルトでは30秒でタイムアウトします)。
参考までに上記のコードをPlaywrightで書き直すと、以下のような感じです。
from playwright.sync_api import sync_playwright
# ログイン情報
LOGIN_URL = "https://example.com/login"
EMAIL = "your_email@example.com"
PASSWORD = "your_password"
with sync_playwright() as p:
# ブラウザを起動
browser = p.chromium.launch()
page = browser.new_page()
# ログインページにアクセス
page.goto(LOGIN_URL)
# メールアドレスとパスワードを入力
page.get_by_placeholder("name@example.com").fill(EMAIL)
page.get_by_placeholder("password").fill(PASSWORD)
# ログインボタンをクリック
page.get_by_role("button").click()
# ページ遷移を待つ
page.wait_for_load_state("networkidle")
# ログイン成功の確認
if "Dashboard" in page.title():
print("ログイン成功!")
else:
print("ログイン失敗")
# ブラウザを閉じる
browser.close()
2. 安定した動作
Seleniumで開発していたときはこの待機周りでかなり苦戦してしまうことが多く、しぶしぶtime.sleepを使ったり、whileで欲しい要素が見つかるまで待つ…みたいな力業をやっていたりもしていて、そのせいかかなり動作が不安定でした。
一方、Playwrightでは自動待機のおかげでtime.sleepもwhileループも不要になりました。
そのおかげなのかPlaywrightの品質が高いのか、自動化スクリプトが失敗することはほぼ無くなりました。これが非常にありがたかったです。
3. コードがスマートに書ける
待機を自分で書かなくてよくなった結果、コードの見通しが良くなりました。
またAPIが良く設計されているおかげか、操作をそのままコードに落とし込んだかのように書ける気がします(主観)。
4. 認証状態の保存・読み込みが簡単
Playwrightはブラウザコンテキストと呼ばれる独立した環境で実行されます。
なので基本的に状態を持たず、それによってテスト同士が干渉しあうことなく独立して実行されます。
しかし今回はブラウザ操作の自動化が目的だったので、例えば一度ログインした後は認証情報を使いまわして次回以降のログイン処理をできるだけしないようにしたい、と思っていました。
そういったこともPlaywrightでは簡単に実現できます。クッキーやローカルストレージの情報をjsonで保存しておいて、以下のように保存・読み込みを行うだけです(公式ドキュメントより引用)
# Save storage state into the file.
storage = context.storage_state(path="state.json")
# Create a new context with the saved storage state.
context = browser.new_context(storage_state="state.json")
5. 公式ドキュメントが読みやすい、求めている情報を探しやすい
公式ドキュメントは英語しかありませんが、かなり分かりやすくまとまっている印象です。
少なくとも今回やりたいことは全て公式ドキュメントを見ることで解決できました。
信頼できる情報源が分かりやすいというのは非常にありがたいですね。
まとめ
公式ページにもあるように元々はE2Eテストでの利用を目的に開発されたものだと思いますが、今回はブラウザ操作自動化に焦点をあててPlaywrightを紹介してみました。
Playwrightは2020年にリリースされたものということでSeleniumと比較すると歴が浅く、日本語での解説記事などもSeleniumと比較すると少なくとっつきづらい印象があるかもしれません。しかし、ブラウザ操作自動化の知見がほぼ無い私でも簡単に使える、非常に便利なツールだと感じました。
みなさんもぜひ使ってみてください!
Discussion