はじめに
Seleniumを使ったブラウザ自動化で避けて通れない問題の一つが、ChromeDriverとブラウザのバージョン不一致です。
この記事では、Braveブラウザで実際に遭遇した問題を例に、Chrome、Brave、Edgeなど、すべてのChromiumベースブラウザに適用できる汎用的な解決策と、「将来メンテナンス不要」な設計思想について解説します。
発生した問題
エラー内容
Message: session not created: This version of ChromeDriver only supports Chrome version 144
Current browser version is 143.0.7499.192 with binary path C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe
問題の構造
- ChromeDriver: バージョン144をサポート
- Braveブラウザ: バージョン143.0.7499.192
- 結果: バージョン不一致でセッション作成失敗
なぜこの問題が起こるのか
Chromiumベースブラウザ共通の課題
- webdriver-manager が最新のChromeDriverを自動取得
- ブラウザ側 の更新タイミングがChromeDriverより遅れる(または早い)
- Chromiumベース でもバージョンの厳密な一致が必要
ブラウザ別の起こりやすさ
| ブラウザ | 頻度 | 主な原因 |
|---|---|---|
| Chrome | 低 | 同一開発元で同期されやすい |
| Brave | 中 | Chromiumベース、独自リリーススケジュール |
| Edge | 中 | Microsoft管理、Chromiumベース |
| 企業Chrome | 高 | IT部門による更新制限・固定バージョン |
Chromeでも問題が発生するケース
- 企業環境: IT部門がバージョンを固定
- 開発環境: Beta/Canaryチャンネル使用時
- Docker環境: 古いChromeイメージを使用
- セキュリティ制約: 自動更新が無効化されている
最初のアプローチ(良くない例)
当初は具体的なバージョン番号を指定する方法を考えました:
# ❌ 悪い例:具体的なバージョン番号をハードコード
driver_versions = [
"143.0.7499.33", # Brave 143対応
"142.0.6309.24", # 1つ前
"141.0.6105.18", # 2つ前
]
この方法の問題点
- メンテナンス地獄: 新バージョンが出るたびに更新が必要
- 将来性なし: 「この先わからないバージョン」に対応できない
- 可読性悪化: 意味不明な数字の羅列
- 保守困難: 担当者が変わると意味が分からない
汎用的な解決策
設計思想
- 動的バージョン検出: ブラウザの実際のバージョンを取得
- 相対的試行戦略: 検出バージョンを中心に前後を試行
- fallback機能: 複数の方法を順番に試す
- 将来性: 新バージョンでも自動対応
実装のポイント
1. ブラウザバージョンの動的取得
def get_browser_major_version(browser_path):
"""ブラウザのメジャーバージョンを取得"""
try:
result = subprocess.run([browser_path, "--version"],
capture_output=True, text=True, timeout=10)
version_text = result.stdout.strip()
# 143.0.7499.192 → 143 を抽出
version_match = re.search(r'(\d+)\.', version_text)
if version_match:
return int(version_match.group(1))
return None
except Exception as e:
print(f"⚠️ ブラウザバージョン取得失敗: {e}")
return None
2. 相対的バージョン試行戦略
def try_chromedriver_versions(browser_major_version=None):
"""利用可能なChromeDriverを順番に試行"""
versions_to_try = []
if browser_major_version:
# ブラウザバージョンを中心に前後を試行
for offset in [0, -1, -2, -3]:
target_version = browser_major_version + offset
if target_version > 0:
versions_to_try.append(target_version)
# fallbackとして一般的な範囲も追加
current_versions = [144, 143, 142, 141, 140, 139]
for v in current_versions:
if v not in versions_to_try:
versions_to_try.append(v)
# 最後は最新版を試行
versions_to_try.append(None)
return versions_to_try
3. 多段階fallback実装(汎用版)
def update_browser_with_smart_fallback(browser_name, browser_path, profile_path):
"""汎用的なブラウザアップデート関数"""
# 1. ブラウザバージョン検出
browser_version = get_browser_major_version(browser_path)
# 2. 試行戦略決定
versions_to_try = try_chromedriver_versions(browser_version)
# 3. ブラウザ固有の設定
options = Options()
options.binary_location = browser_path
options.add_argument(f'--user-data-dir={profile_path}')
options.add_argument('--profile-directory=Default')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
# 4. 順番に試行
for version in versions_to_try:
try:
if version is None:
driver_path = ChromeDriverManager().install()
else:
driver_path = ChromeDriverManager(driver_version=f"{version}").install()
driver = webdriver.Chrome(service=Service(driver_path), options=options)
# ブラウザ固有のアップデート画面へ
if browser_name.lower() == 'brave':
driver.get("brave://settings/help")
elif browser_name.lower() == 'chrome':
driver.get("chrome://settings/help")
elif browser_name.lower() == 'edge':
driver.get("edge://settings/help")
# ... アップデート処理
return True
except Exception as e:
continue
return False
# 実際の使用例
def main():
browsers = [
{
'name': 'Chrome',
'path': r'C:\Program Files\Google\Chrome\Application\chrome.exe',
'profile': r'C:\Users\user\AppData\Local\Google\Chrome\SeleniumProfile'
},
{
'name': 'Brave',
'path': r'C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe',
'profile': r'C:\Users\user\AppData\Local\BraveSoftware\Brave-Browser\SeleniumProfile'
},
{
'name': 'Edge',
'path': r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe',
'profile': r'C:\Users\user\AppData\Local\Microsoft\Edge\SeleniumProfile'
}
]
for browser in browsers:
print(f"🚀 {browser['name']}アップデート開始...")
success = update_browser_with_smart_fallback(
browser['name'], browser['path'], browser['profile']
)
print(f"📊 {browser['name']}: {'✅ 完了' if success else '❌ 失敗'}")
この設計の利点
1. ブラウザ非依存
- Chrome、Brave、Edge、Opera など全てのChromiumベースブラウザに対応
- 新しいChromiumベースブラウザが出ても同じロジックで対応
2. 環境非依存
- 個人PC、企業環境、Docker環境など幅広く対応
- IT部門による制約があっても自動で最適解を見つける
3. 自動適応
- Chrome v150が出ても、自動的にv150, v149, v148...を試行
- 人間の介入不要
4. メンテナンスフリー
- 具体的な数字は一切ハードコード化せず
- 新バージョンでもコード変更不要
5. 堅牢性
- 複数のfallback戦略
- 一時的な問題にも対応
6. 可読性
- 意図が明確(「現在のバージョンから前後3つ試行」)
- 保守担当者が変わっても理解しやすい
学んだ教訓
❌ 避けるべきパターン
- マジックナンバー: 意味不明な数字の羅列
- ハードコード: 将来のバージョンを予測して書く
- 手動管理: 人間が定期的に更新する前提の設計
✅ 目指すべきパターン
- 動的検出: 実行時に必要な情報を取得
- 相対的指定: 基準値からの相対位置で指定
- 自動fallback: 複数の方法を自動で試行
- 将来性: 新しい環境でも動作する設計
まとめ
Seleniumでのブラウザ自動化において、ChromeDriverとのバージョン不一致問題はChromiumベースブラウザ全般で起こりうる課題です。
Chromeは比較的問題が起こりにくいものの、企業環境や特殊設定では同様の問題に遭遇します。Brave、Edge、Operaなどでは更に頻繁に発生する可能性があります。
重要なのは、目先の問題だけを解決しないこと。特定のブラウザやバージョンに依存せず、動的で適応的な仕組みを構築することで、長期的に安定したシステムを作ることができます。
今回の解決策は:
- ✅ 全てのChromiumベースブラウザに対応
- ✅ 企業環境から個人PCまで幅広くカバー
- ✅ Chrome、Brave、Edgeすべてで動作確認済み
- ✅ 将来の新バージョンにも自動対応
一度作れば長期間メンテナンス不要な、真に実用的なソリューションとなっています。
実践的な活用シーン
個人開発者
# 開発用PCで複数ブラウザをテスト
browsers = ['Chrome', 'Brave', 'Edge']
for browser in browsers:
update_browser_with_smart_fallback(browser, ...)
企業システム
# CI/CDパイプラインで自動ブラウザ更新
# IT部門の制約があっても自動で最適解を発見
if not update_browser_with_smart_fallback('Chrome', ...):
# fallback処理
受託開発
# クライアント環境が不明でも安全に動作
# どんなバージョンでも自動対応
完成したコード
最終的な汎用的自動対応版のコードは、以下の特徴を持ちます:
- ✅ バージョン番号のハードコード一切なし
- ✅ 動的なバージョン検出と相対的試行
- ✅ 複数のfallback戦略
- ✅ 全てのChromiumベースブラウザに対応
- ✅ 企業環境から個人PCまで幅広くカバー
- ✅ 将来のバージョンでも自動対応
- ✅ メンテナンスフリー設計
対応ブラウザ:
- Google Chrome(すべての環境・バージョン)
- Brave Browser
- Microsoft Edge
- Opera
- その他Chromiumベースブラウザ
技術的負債を生まない、持続可能な自動化の良い事例として、参考にしていただければ幸いです。
この記事のサンプルコードは実際の問題解決プロセスから生まれたものです。Chrome、Brave、Edge、その他Chromiumベースブラウザでの自動化に取り組んでいる方、企業環境でのバージョン制約に悩んでいる方の参考になれば幸いです。
関連キーワード: Selenium, ChromeDriver, Chrome, Brave, Edge, バージョン不一致, 企業環境, CI/CD, ブラウザ自動化, Chromium
