1. 結論(この記事で得られること)
Selenium の headless モードが動かない原因は、環境差異・オプション不足・タイミング問題の3つに集約されます。
この記事では:
- 現場で頻出する5大エラーパターンと即効性のある解決策
- AI(Claude/ChatGPT)を使った最速デバッグフロー
- CI/CD環境で安定稼働させるための実装パターン
- 本番運用で役立つ監視・リトライ設計
を実コード付きでお伝えします。
私も昔、Jenkins上で動かないheadlessテストに3時間溶かしたことがあります。あの時この知識があれば……というエッセンスを詰め込みました。
2. 前提(環境・読者層)
想定読者
- Selenium でスクレイピングやE2Eテストを書いている
- ローカルでは動くのにCI/Docker/本番で動かない経験がある
- headless化したいがエラーが出て困っている
検証環境
Python: 3.10+
Selenium: 4.15.0+
Chrome/ChromeDriver: 120+ (Chrome for Testing推奨)
OS: Ubuntu 22.04 (Docker), macOS, Windows
前提知識
- Selenium の基本的な使い方は知っている
- Web要素の取得(find_element等)は経験済み
3. Before:よくあるつまずきポイント
3-1. 「ローカルでは動くのにDockerで動かない」
最頻出パターンです。私も新人時代にこれで半日潰しました。
# ❌ ローカルでしか動かないコード
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
エラー例
selenium.common.exceptions.WebDriverException:
Message: unknown error: Chrome failed to start: exited abnormally
3-2. 要素が取得できない
headlessにした途端に 「NoSuchElementException」 が頻発。
driver.get('https://example.com')
element = driver.find_element(By.ID, 'submit-button') # ❌ 見つからない
3-3. スクリーンショットが真っ白
driver.save_screenshot('debug.png') # 画面が真っ白 or 途中で切れている
3-4. バージョン不一致エラー
selenium.common.exceptions.SessionNotCreatedException:
Message: session not created: This version of ChromeDriver only supports Chrome version 120
3-5. メモリ不足でクラッシュ
CI環境で複数テスト実行時に謎の異常終了。
4. After:基本的な解決パターン
4-1. 必須オプションセット(Docker/CI対応版)
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def create_headless_driver():
"""本番環境で安定動作する headless driver"""
options = webdriver.ChromeOptions()
# 🔹 headless 必須オプション
options.add_argument('--headless=new') # 旧headlessより安定
options.add_argument('--no-sandbox') # Docker必須
options.add_argument('--disable-dev-shm-usage') # メモリ不足対策
options.add_argument('--disable-gpu') # Linux必須
# 🔹 検出回避・安定化オプション
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
options.add_argument('--window-size=1920,1080') # サイズ明示
# 🔹 パフォーマンス改善
options.add_argument('--disable-extensions')
options.add_argument('--disable-logging')
options.add_argument('--log-level=3')
# Page Load Strategy(必要に応じて)
options.page_load_strategy = 'normal' # 'eager' or 'none' も選択肢
driver = webdriver.Chrome(options=options)
driver.set_page_load_timeout(30)
driver.implicitly_wait(10)
return driver
各オプションの意味
「--headless=new」
理由: Chrome 109以降の新実装。旧版より描画が正確
「--no-sandbox」
理由: Docker等でroot実行時に必須(セキュリティ低下に注意)
「--disable-dev-shm-usage」
理由: 「/dev/shm」の容量不足対策。Dockerで頻出
「--disable-gpu」
理由: Linux環境でGPU未搭載時の異常終了を防ぐ
「--window-size」
理由: viewport未指定だとレスポンシブ崩れで要素が取れない
4-2. タイミング問題の解決
def safe_get_element(driver, by, value, timeout=10):
"""要素が確実に取得できるまで待機"""
try:
element = WebDriverWait(driver, timeout).until(
EC.presence_of_element_located((by, value))
)
return element
except TimeoutException:
# デバッグ用にスクリーンショット保存
driver.save_screenshot(f'error_{value}.png')
driver.save_screenshot('error_full.png')
with open('error_page_source.html', 'w', encoding='utf-8') as f:
f.write(driver.page_source)
raise
# 使用例
driver = create_headless_driver()
driver.get('https://example.com')
submit_btn = safe_get_element(driver, By.ID, 'submit-button')
submit_btn.click()
4-3. ChromeDriver バージョン自動管理
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def create_driver_with_auto_update():
"""ChromeDriverを自動ダウンロード・更新"""
options = webdriver.ChromeOptions()
options.add_argument('--headless=new')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
return driver
requirements.txt
selenium>=4.15.0
webdriver-manager>=4.0.0
4-4. Dockerfile サンプル
FROM python:3.10-slim
# Chrome インストール
RUN apt-get update && apt-get install -y \
wget \
gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
&& apt-get update \
&& apt-get install -y google-chrome-stable \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]