こんにちは、SIの楊です!

Seleniumを長期間で使用していると、特に頻繁に自動更新されるChromeブラウザにおいて、ドライバのバージョン不一致による問題が発生することがあります。

本記事では、この問題を解決するために調べたの二つの方法を紹介します。

方法1. CfTのAPIを使用して最新のChrome Driverを更新する

Chrome 115バージョンから、Googleはテストと自動化に特化した「CfT」ー「Chrome for Testing」をリリースしました。この新バージョンは、開発者が安定した環境でテストできるように、自動更新を管理し、特定のバージョンのChrome関連ファイルを提供します。

CfT(Chrome for Testing)のGitHubページでは、一連のJSON APIエンドポイントが提供されています。今回重要なのは、最新バージョンのダウンロードURLを取得できるlast-known-good-versions-with-downloads.jsonのエンドポイントです。

このエンドポイントにアクセスすると、最新バージョンのChromeDriverのダウンロードURLを含むJSON情報が以下となります。

{
  ...
  "channels": {
    "Stable": {
      "channel": "Stable",
      "version": "124.0.6367.91",
      "revision": "1274542",
      "downloads": {
        "chrome": [
          ...
        ],
        "chromedriver": [
          {"platform": "linux64", "url": "..."},
          {"platform": "mac-arm64", "url": "..."},
          {"platform": "mac-x64", "url": "..."},
          {"platform": "win32", "url": "..."},
          {"platform": "win64", "url": "..."}
        ],
        "chrome-headless-shell": [
          ...
        ]
      }
    },
    "Beta": {...},
    "Dev": {...},
    "Canary": {...}
  }
}

先程のJSONを取得したら、解析を行い、対応するチャンネルとプラットフォームのURLを抽出することができます。

また、JSON内バージョンの情報も含めているので、バージョンをチェックする機能を追加することに、毎回実行する際にドライバを再ダウンロードする必要を避け、必要な時にのみ自動的にダウンロードすることができます。

以下の例は、ダウンロード機能のみとなります。

/**
 * JSONデータから、特定のChromeDriverのダウンロードURLを取得するメソッド。
 * @param jsonData JSON形式の文字列データ。
 * @param channel チェックするチャンネル名(例:"Stable")。
 * @param platform 対象のプラットフォーム(例:"win64")。
 * @return ダウンロードURL。該当するURLが見つからない場合はnullを返す。
 */
private static String getDownloadUrl(String jsonData, String channel, String platform) {

    // JSON文字列からJSONObjectを生成
    JSONObject jsonObject = new JSONObject(jsonData);
    
    // チャンネルとプラットフォームに基づいて、対象のドライバー情報を含むJSONArrayを取得
    JSONArray drivers = jsonObject.getJSONObject("channels")
                                 .getJSONObject(channel)
                                 .getJSONObject("downloads")
                                 .getJSONArray("chromedriver");

    // JSONArrayをループして、指定されたプラットフォームに一致するURLを探す
    for (int i = 0; i < drivers.length(); i++) {
        JSONObject driver = drivers.getJSONObject(i);
        if (driver.getString("platform").equals(platform)) {
            return driver.getString("url");  // 一致するURLを見つけたら、そのURLを返す
        }
    }
    return null; // 該当するプラットフォームのURLが見つからない場合はnullを返す
}

取得したURLを利用し、ChromeDriverのZIPファイルをダウンロードします。

/**
 * 指定されたURLからファイルをダウンロードして、一時ファイルとして保存します。
 * @param urlString ダウンロードするファイルのURL
 * @return ダウンロードされたファイルへのFileオブジェクト
 * @throws IOException 接続エラーやファイル操作の例外が発生した場合にスローされます
 */
public static File downloadFile(String urlString) throws IOException {

    // URLオブジェクトを作成
    URL url = new URL(urlString); 

    // URLへ接続
    HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
    connection.connect(); 

    // 一時ファイルを作成
    File tempFile = File.createTempFile("chromedriver", ".zip"); 
    try (InputStream in = connection.getInputStream();  
         FileOutputStream out = new FileOutputStream(tempFile)) { 
        in.transferTo(out); 
    }

    return tempFile; // 一時ファイルを返す
}

注意が必要なのは、この時点で取得しているのはドライバが含まれたZIPファイルであるため、ドライバを取得するにはファイルを解凍し、保存する必要があります。

方法2. WebDriverManagerのライブラリを使用する

WebDriverManagerは、Selenium WebDriverが必要とするドライバー(例:chromedriver、geckodriver、msedgedriverなど)のダウンロード、設定、維持を全自動で行うオープンソースのJavaライブラリです。(WebDriverManagerGithubページより)

まずはMavenを使用する際、pom.xmlWebDriverManager のライブラリ情報の追加を行います。

もしChromeの更新によりエラーが出た場合はWebDriverManagerの Github リリースページをチェックして、最新のバージョンを使いましょう(2024年5月まではVersion 5.8.0です)。

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>io.github.bonigarcia</groupId>
      <artifactId>webdrivermanager</artifactId>
      <version>5.8.0</version>
    </dependency>
    ...
  </dependencies>
</project>

そして、Javaで以下のコードを通じて最新のドライバーを使用できるようになります。

// ドライバーのセットアップを行います。
WebDriverManager.chromedriver().setup();

// Chromeの起動オプションを希望すれば、設定するためのオブジェクトを生成します。
ChromeOptions options = new ChromeOptions();

// Chromeドライバーのインスタンスを生成します。
WebDriver driver = new ChromeDriver(options);

これらの方法により、Chromeが更新されるたびに、対応するChromeDriverも自動的に更新され、自動化テストの連続性と安定性が保たれます。