SeleniumでChrome が起動しない問題の解決記録 [DevToolsActivePort file doesn’t exist]

ホームディレクトリを持たないサービスユーザーで Selenium(Python)から Chrome をヘッドレス起動しようとしたところ、SessionNotCreatedException が発生して起動できなかった。原因の特定に手間取ったため、調査の過程を記録しておく。

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: Chrome failed to start: exited normally.
  (session not created: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /usr/bin/google-chrome is no longer running,
   so ChromeDriver is assuming that Chrome has crashed.)

「exited normally(正常終了)」という点が特徴的。クラッシュではなく Chrome が意図的に終了していた。今回、デーモンプロセス用に作成したユーザーで実行しており、ホームディレクトリーが無いのが原因かと思って、書き込み可能なパスを --user-data-dir で明示したが変わらず。

原因

chromedriverのログを調べたら以下の記録を発見。

[INFO]: Launching chrome: /usr/bin/google-chrome --headless --user-data-dir=/var/www/jpp-reference/chrome-data ...
mkdir: cannot create directory '/home/jpp': Permission denied
touch: cannot touch '/home/jpp/.local/share/applications/mimeapps.list': No such file or directory
chrome_crashpad_handler: --database is required

/usr/bin/google-chrome は実体バイナリではなくシェルのラッパースクリプトになっており、起動時に $HOME 配下へのファイル書き込みを試みる。ホームディレクトリーが存在しないため、この処理で失敗して Chrome が即座に終了していた。

--user-data-dir を指定しても、ラッパースクリプトが $HOME を参照するタイミングはそれより前であるため、この指定だけでは回避できないということだった。

解決

ChromeDriver の起動時に HOME 環境変数を書き込み可能なディレクトリへ上書きする。

service_env = {**os.environ, ‘HOME’: ‘/tmp/chrome-data’}

srv = webdriver.chrome.service.Service(
executable_path=’/usr/bin/chromedriver’,
env=service_env,
)

ChromeDriver はこの環境変数を Chrome プロセスに引き継ぐため、ラッパースクリプトが参照する $HOME が書き込み可能なディレクトリになり、起動が成功した。