Playwright実践編:待機する

プログラミング

概要

Webスクレイピングをするとページのロードや要素の確認をしてからデータを取得するというパターンがちょこちょこあります。

Playwrightは、最低限の待機を自動で行ってくれる上、指定したイベントまで待つための構文も充実しています。

以下では、テスト用のHTMLを基に、主な待機の技術を解説します。

テスト用のWebページ

こちらにテスト用のWebページを用意しました。

Playwright Test

このWebページは、ページの読み込み完了から3秒後にボタンを表示します。
ボタンは、クリックされると青から緑に色が変わります。
そしてWebAPI(モック)からデータを読み込みます。

以下は、テスト用のHtmlのコードです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Playwright Test</title>
    <style>
        #submit-button {
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 5px;
            transition: background-color 0.3s ease;
        }

        #submit-button.clicked {
            background-color: #28a745; /* 緑色 */
        }
    </style>
    <script>
        document.addEventListener("DOMContentLoaded", () => {
            setTimeout(() => {
                const button = document.createElement("button");
                button.id = "submit-button";
                button.textContent = "Submit";
                document.body.appendChild(button);

                // ボタンクリックでAPIリクエストを模擬し、色を変更
                button.addEventListener("click", () => {
                    button.classList.add("clicked"); // クラスを追加して色を変更
                    fetch("https://task.x0.com/playwright-test241222-01.php")
                        .then(response => response.json())
                        .then(data => {
                            console.log("API Response:", data);
                        });
                });
            }, 3000); // 3秒後にボタンを表示
        });
    </script>
</head>
<body>
    <h1>Playwright Test Page</h1>
    <p>ボタンが3秒後に表示されます。</p>
</body>
</html>

 

1. ページのロードを待機する

Webページを読み込み終わるまで待機するコードです。

読み込みが完了するまで待機しないとすべての要素が表示される前にWebスクレイピングを行ってしまい、正常にデータが取得できない場合があります。
そのような場合は、読み込み完了まで待機する必要があります。

コード例

from playwright.sync_api import sync_playwright
from tkinter import Tk, Label, Button
# Tkinterで結果表示用ダイアログを定義
def show_message(message):
    def on_ok():
        root.destroy()
    root = Tk()
    root.title(“結果”)
    Label(root, text=message, padx=20pady=10).pack()
    Button(root, text=“OK”command=on_ok, padx=10pady=5).pack()
    root.mainloop()
with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)  # ヘッドレスモードを無効化
    page = browser.new_page()
    page.goto(“https://task.x0.com/playwright-test241222-01.html”)
    # DOMContentLoaded まで待機
    page.wait_for_load_state(“domcontentloaded”)
    show_message(“Page content loaded.”)
    browser.close()

 

page.wait_for_load_state("domcontentloaded")

このコードでページの読み込み完了まで待機します。

2. 要素(ボタン)の表示まで待機する

Webページがコード的には読み込み完了してもJavaScriptやほかの要因で、要素が後から表示される場合があります。
また、ページの読み込みが完了していなくても要素さえ表示されていればデータが取得できる場合があります。
この場合は、要素が出現した段階でデータを取得したほうが処理が早くなります。

この例では、JavaScriptで3秒間ボタンの表示を遅らせています。
Webページの読み込みが完了し、3秒後にボタンが表示されるのを待機しています。

コード例

from playwright.sync_api import sync_playwright
from tkinter import Tk, Label, Button

# Tkinterで結果表示用ダイアログを定義
def show_message(message):
    def on_ok():
        root.destroy()

    root = Tk()
    root.title("結果")
    Label(root, text=message, padx=20, pady=10).pack()
    Button(root, text="OK", command=on_ok, padx=10, pady=5).pack()
    root.mainloop()

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)  # ヘッドレスモードを無効化
    page = browser.new_page()
    page.goto("https://task.x0.com/playwright-test241222-01.html")

    # IDが"submit-button"の要素が表示されるまで待機
    page.wait_for_selector("#submit-button")
    show_message("Submit button is visible.")

    browser.close()
page.wait_for_selector("#submit-button")

idが “#submit-button” である要素が表示されるのを待ちます。

3. データの読み込みを待機する

Webページ内で何かのデータを読み込んで処理が行われる場合があります。
そのようなデータを取得する場合は、データの読み込みが終わるのを待機して、Webスクレイピングを行わなければなりません。

以下のコードでは、PlaywrightでWebページのボタンを押してそのことによってデータを取得します。

コード例

from playwright.sync_api import sync_playwright
from tkinter import Tk, Label, Button

# Tkinterで結果表示用ダイアログを定義
def show_message(message):
    def on_ok():
        root.destroy()

    root = Tk()
    root.title("結果")
    Label(root, text=message, padx=20, pady=10).pack()
    Button(root, text="OK", command=on_ok, padx=10, pady=5).pack()
    root.mainloop()

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)  # ヘッドレスモードを無効化
    page = browser.new_page()
    page.goto("https://task.x0.com/playwright-test241222-01.html")

    # ボタンが表示されるまで待機
    page.wait_for_selector("#submit-button")
    print("Button found, clicking...")
    page.click("#submit-button")

    # APIリクエストを監視
    api_url = "https://task.x0.com/playwright-test241222-01.php"
    with page.expect_response(
        lambda response: api_url in response.url
    ) as response_info:
        print("Waiting for the API response...")

    # レスポンスの内容を確認
    response = response_info.value
    print("Response captured.")
    show_message(
        f"Response received: {response.status},"
        f"Content: {response.body().decode('utf-8')}"
    )

    browser.close()


 

    page.click("#submit-button")

ボタンをクリックします。

    with page.expect_response(
        lambda response: api_url in response.url
    ) as response_info:
        print("Waiting for the API response...")

page.expect_response()でレスポンスがあるまで待機して、
レスポンスは response_info へ格納されます。

lambda response: api_url in response.url

page.expect_response(引数)は、指定した条件に一致するHTTPリクエストのレスポンスを取得します。
この場合は、response.url に api_url が含まれていればレスポンスを取得します。
resposeオブジェクトは、

  • url: レスポンスに対応するリクエストのURL。
  • status: HTTPステータスコード(例: 200, 404)。
  • status_text: ステータスコードに対応するテキスト(例: “OK”, “Not Found”)。
  • body(): レスポンスボディの内容を取得する非同期メソッド。
  • headers: レスポンスヘッダーを取得する辞書。

などのプロパティを持ちます。

response_info.value

レスポンスから値を取得します。

まとめ

Playwrightを使ってWebスクレイピングをするときの待機のパターン3種類を説明しました。

  • ページの読み込みを待機
  • 要素の読み込みを待機
  • データの読み込みを待機

スクレイピングテスト用のWebページで色々試してみてください。
書き換えて試してみると、理解が深まります。

Commnts