0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Selenium headlessモードが動かない原因まとめ|AI実務ノート 編集部

Last updated at Posted at 2026-01-03

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"]
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?