更新日: ・ 自動化ノートの管理人

Playwrightで「Executable doesn't exist」になる原因と直し方(別のvenvが共有のブラウザを消すことがある)

毎日自動で動かしていたPythonのPlaywrightスクリプトが、ある日突然、ブラウザを起動できずに止まった。コードは何も変えていない。前日までは動いていた。

これは私が実際にはまった例です。原因は、ブラウザ本体が複数のプロジェクトで共有されていて、別のプロジェクトの操作で消されたことでした。この記事では、何が起きたかと、直し方、再発の防ぎ方をまとめます。

どんなエラーになったか

私の環境のログには、次のような形のエラーが出ていました(パスは置き換えています)。

BrowserType.launch: Executable doesn't exist at
C:\path\to\ms-playwright\chromium_headless_shell-XXXX\...\headless_shell.exe

メッセージには「Playwrightをインストールまたは更新した直後のようです」という趣旨の案内も付いていました。ただ、私のケースでは、そのプロジェクト自体は何も更新していませんでした。真因は、別のプロジェクトがブラウザを消したことです。この案内に引きずられないほうがよいと感じました。なお、このエラー文の形は私の環境のログで見たもので、公式ドキュメントには載っていません。Playwrightの版によって番号や文言は違うはずです。

原因: ブラウザはvenvの外の共有フォルダにある

PlaywrightのPython版は、pip install playwright でライブラリを入れたあと、playwright install でブラウザ本体を別に入れます。公式ドキュメントによると、ブラウザの保存場所は、Windowsでは %USERPROFILE%\AppData\Local\ms-playwright です。venvの中ではないので、同じユーザーの全プロジェクトで共有されます。

さらに、公式ドキュメントには次の説明があります。

つまり、プロジェクトAがPlaywrightの古い版を使い、プロジェクトBが新しい版を使っているとき、Bで playwright install を実行すると、Aが必要とする古い版のブラウザが「誰も使っていない」と判断されて消されることがあります。私の環境では、Aは pip install しただけで playwright install を実行していませんでした。そのため、Aがブラウザの利用者として記録されておらず、消される側に回ったのだと考えています。

起きたこと

  1. 1. 共有の場所ブラウザはvenvの外の ms-playwright に置かれ、全プロジェクトで共有
  2. 2. 別の更新プロジェクトBで新しい版を入れ、playwright install を実行
  3. 3. 掃除される使う利用者がいない古い版のブラウザが削除される
  4. 4. Aが止まる翌日の自動実行で Executable doesn't exist
Aのコードも環境も、何も変えていないのに止まります。

直し方

止まったプロジェクトのvenvで、そのvenvのPythonからブラウザを入れ直します。

"C:\path\to\venv\Scripts\python.exe" -m playwright install chromium

venvを有効化しなくても、python.exe をフルパスで呼べば、そのvenvのPlaywrightの版に合ったブラウザが入ります(この方法はvenvをOneDriveの外に置く話でも使っています)。公式ドキュメントによると、Playwrightにはヘッドレス用の別ビルド(chromium headless shell)があり、playwright install chromium でChromiumが入ります。

私の環境では、他のプロジェクトと同じ版のPlaywrightに揃えてから入れたところ、すでにあるブラウザが再利用され、ダウンロードは発生しませんでした。

再発を防ぐ

方法内容向いている場面
venvを作ったら必ずinstallまでpip install のあとに python -m playwright install chromium まで実行するまず全員がやること。私はこれで止まらなくなった
置き場所を分ける環境変数 PLAYWRIGHT_BROWSERS_PATH で、インストール時と実行時に同じ場所を指定するプロジェクトごとにブラウザを独立させたいとき
自動削除を止めるPLAYWRIGHT_SKIP_BROWSER_GC=1 を設定するか、installに --no-remove を付ける古い版を意図的に残したいとき
入っているEdge・Chromeを使う起動時に channel="msedge" や channel="chrome" を指定するPlaywright用のブラウザを入れたくないとき

PLAYWRIGHT_BROWSERS_PATH は、公式ドキュメントに、ブラウザを特定の場所へ入れさせることと、実行時にその場所を探させることの両方に使えると書かれています。分ける場合は、インストールと実行の両方で同じ値を指定してください。

channel は、Python版では次のように指定します。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(channel="msedge")

公式ドキュメントによると、channel には "chrome"、"msedge" などが指定できます。ただし、既定は同梱のChromiumで、公式ドキュメントでは、多くの場合は既定の設定(最新のChromium)を使うのがよいと説明されています。入っているEdgeやChromeが自動更新されて挙動が変わる可能性は、頭に入れておいてください。

無人実行で早く気づくために

手で動かしているときは、エラーはその場で見えます。毎日の自動実行で怖いのは、失敗に気づかず何日も止まることです。タスクスケジューラの終了コードを記録する、成功の印のファイルを毎回更新して古くなったら通知する、といった仕組みを足しておくと、止まった翌日には気づけます。考え方はタスクスケジューラの失敗に気づく方法 ― 自動実行を毎朝一覧で確かめるでまとめています。また、タスクの組み方はWindowsのタスクスケジューラでClaude Codeを毎日自動で動かすに書いています。

まとめ