Closed5

Playwrightでブラウザ自動操作終了後に継続して手動操作する方法

idumistidumist

実現したいこと

  1. Playwrightでブラウザ操作を途中まで自動化したい。
  2. 続きは手動で操作を継続したい。
  3. 手動操作終了後、手動でブラウザを閉じることで起動元のPlaywrightも正常終了させたい。

→起動元のPlaywrightが終了するとブラウザも当然終了してしまうので、2の時点で何らかの対応が必要。

idumistidumist

前提条件

  • Playwright for .NET 1.50.0
  • インストール済みのGoogle Chrome(Playwrightではブラウザをインストールしない)
  • 通常表示とヘッドレスのどちらも利用するが、今回は手動操作するため通常表示のみ
  • puppeteer/pyppeteerやPower Automateの代替としてブラウザ操作の自動化のみが目的(テスト自動化等の本来の用途は全くわかっていない)
idumistidumist

結論

Task.Delay(-1)で止めてCloseイベントのコールバックでキャンセル処理を行う

  1. 自動操作したいところを通常通り記述する。
  2. 手動操作したいところでTask.Delay(-1, CancellationToken)で止め、手動操作する。
  3. ブラウザを手動で閉じることで、Closeイベントを発生させコールバック内で2をキャンセル処理、ブラウザとPlaywrightを正常終了させる。

その前に試した方法は2つ。

他の方法1 PauseAsync()で止める(用途によっては有効)

  1. 自動操作したいところを通常通り記述する。
  2. 手動操作したいところでPage.PauseAsync()で止め、手動操作する。(Inspectorウィンドウが開く)
  3. InspectorウィンドウのResumeボタン(F8)を押下することで、2以降に処理が戻り、ブラウザとPlaywrightを正常終了させる。

→Inspectorウィンドウが別途開いてしまって鬱陶しい。

他の方法2 Page.IsClosedが変わるのを待つ(安易だけど動く)

  1. 自動操作したいところを通常通り記述する。
  2. 手動操作したいところでwhile (! Page.IsClosed) await Task.Delay(10000);などの適当な無限ループで止め、手動操作する。
  3. ブラウザを手動で閉じることで、Page.IsClosedがtrueに変わって2の無限ループを抜け、ブラウザとPlaywrightを正常終了させる。

→無限ループとTask.Delay()を使うならもっと良い方法がありそう。

idumistidumist

Task.Delay(-1)で止めてCloseイベントのコールバックでキャンセル処理を行う

using Microsoft.Playwright;

// キャンセルトークン
CancellationTokenSource _cancellationTokenSource = new();
var _cancellationToken = _cancellationTokenSource.Token;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new()
{
    Channel = "chrome",  // インストール済みのChromeを起動
    Headless = false  // trueならヘッドレス
});
var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();

// ブラウザのCloseイベント発生時の処理
page.Close += (_, _) =>  // 非同期処理がある場合は async (_, _) =>
{
    // ブラウザがCloseされたタイミングでキャンセル実行
    _cancellationTokenSource.Cancel();
    _cancellationTokenSource.Dispose();
};

// 自動操作を書く
await page.GotoAsync("https://example.jp");
// ClickAsync()や
// FillAsync()など
// ここまでで自動操作終了

// ここから手動操作に移る
try
{
    // キャンセルされるまで待つ
    await Task.Delay(-1, _cancellationToken);
}
catch (Exception) {}

await context.CloseAsync();
await browser.CloseAsync();

https://playwright.dev/dotnet/docs/events
https://qiita.com/toRisouP/items/60673e4a39319e69fbc0

idumistidumist

他の方法1 PauseAsync()で止める(用途によっては有効)

// キャンセルトークンとブラウザのCloseイベント発生時の処理は不要
// ここから手動操作に移る、の try~catch を以下に書き換え
await page.PauseAsync();

他の方法2 Page.IsClosedが変わるのを待つ(安易だけど動く)

// キャンセルトークンとブラウザのCloseイベント発生時の処理は不要
// ここから手動操作に移る、の try~catch を以下に書き換え
while (! page.IsClosed) await Task.Delay(10000);
このスクラップは2025/02/12にクローズされました