ログイン自動化は簡単そうに見えます。
IDを入れて、パスワードを入れて、ボタンを押すだけ。そう思って始めたら、私は2時間溶かしました。原因の半分はセレクタ、残り半分は待機です。
夜中にコーヒーを飲みながら、ログインボタンを15回押す自動化を見つめる時間は、なかなか味があります。
最初に知るべきこと
Playwrightで大事なのは、クリックより待機です。
人間は画面が表示されるまで自然に待ちます。でもコードは待ちません。要素がまだ出ていないのに入力しようとして落ちます。ページ遷移の途中で次の処理に進んで落ちます。
私が最初に書いたコードは、見た目だけは正しそうでした。でも実行すると3回に1回失敗しました。自動化で一番困るのは、毎回ではなく、ときどき落ちることです。
動く最小コード
Python版Playwrightで、ログインの基本形はこうです。
from playwright.sync_api import sync_playwright, expect
LOGIN_URL = "https://example.com/login"
def main() -> None:
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(LOGIN_URL, wait_until="domcontentloaded")
page.get_by_label("Email").fill("user@example.com")
page.get_by_label("Password").fill("password")
with page.expect_navigation():
page.get_by_role("button", name="Log in").click()
# ハマりポイント: 遷移後に見える要素で成功判定する
expect(page.get_by_text("Dashboard")).to_be_visible(timeout=10000)
browser.close()
if __name__ == "__main__":
main()
これはサンプルなので、実際のラベルやボタン名は対象サイトに合わせてください。重要なのは、expect_navigation と成功判定を入れていることです。
私が踏んだ4つの穴
1つ目は、CSSセレクタに頼りすぎたことです。
#login > div:nth-child(2) > input のようなセレクタは、見た瞬間に不安になります。画面構造が少し変わるだけで壊れます。可能なら get_by_label や get_by_role を使うほうが読みやすく、壊れにくいです。
2つ目は、ログイン成功の判定をURLだけにしたことです。
URLが変わっても、実はエラー表示が出ていることがあります。成功後に見えるテキストや見出しで確認したほうが安心です。
3つ目は、ヘッドレスでいきなり走らせたことです。
最初は headless=False にして、ブラウザの動きを見たほうが速いです。何が起きているか分からない自動化ほど怖いものはありません。
4つ目は、認証情報をコードに書いたことです。検証用とはいえ、よくありません。環境変数に逃がします。
環境変数版
少しだけ実用に寄せるとこうなります。
import os
from playwright.sync_api import sync_playwright, expect
def main() -> None:
login_url = os.environ["LOGIN_URL"]
user = os.environ["LOGIN_USER"]
password = os.environ["LOGIN_PASSWORD"]
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(login_url, wait_until="domcontentloaded")
page.get_by_label("Email").fill(user)
page.get_by_label("Password").fill(password)
page.get_by_role("button", name="Log in").click()
# ハマりポイント: 固定秒sleepではなく、見えるべき要素を待つ
expect(page.get_by_text("Dashboard")).to_be_visible(timeout=10000)
browser.close()
if __name__ == "__main__":
main()
固定の sleep(5) を入れたくなりますが、できるだけ避けます。速い時は無駄に待ち、遅い時は足りません。
自動化してはいけない瞬間
ログイン自動化は便利ですが、何でも自動化してよいわけではありません。
二段階認証、利用規約で禁止されている操作、人間の確認が必要な送信処理。このあたりは慎重に扱うべきです。
私のルールは、最初は「見るだけ」「下書きまで」「送信しない」です。クリック1つで外部に影響が出る操作は、最後に人間が確認します。
失敗時の証拠を残す
Playwrightで落ちた時、ログだけでは分からないことがあります。
私は最初、エラー文を読んで3回ほど見当違いの修正をしました。実際には、ログイン画面に小さなエラーメッセージが出ていただけです。スクリーンショットを撮っていれば5分で気づけました。
from pathlib import Path
def save_debug(page, name: str) -> None:
Path("debug").mkdir(exist_ok=True)
page.screenshot(path=f"debug/{name}.png", full_page=True)
Path(f"debug/{name}.html").write_text(
page.content(),
encoding="utf-8",
)
ハマりポイントは、成功時ではなく失敗時に呼ぶことです。毎回保存するとファイルが増えすぎますが、例外時だけなら原因調査に効きます。
自動化は、動いた時より落ちた時の情報量で品質が決まります。
まとめ
Playwrightのログイン自動化は、20行でも十分始められます。
ただし、安定させるにはセレクタ、待機、成功判定の3つが必要です。私は2時間ハマって、結局そこに戻ってきました。
ブラウザ自動化で本当に書くべきなのは、クリック手順ではなく、失敗した時に止まれる確認です。

コメント