🚗
【C#】Chromeドライバを自動ダウンロードする
はじめに
突然Seleniumが動かなくなりました。
自動でドライバのダウンロードするようにしていたはずなんですが、いったいなぜ。
Chromeドライバのダウンロードページをのぞいてみると、以下の記述が。
以下、翻訳です。
バージョン 115 以降、Chromeドライバの提供方法が「Chrome for Testing」という方法に変更したようです。
Chrome本体とChromeドライバがセットでバージョン管理されるようになりました。また、JSON API エンドポイントから各バージョンのファイルURLも取得できるようになっています。
今までダウンロードしていたスクリプトが使用できなくなったため、JSON API エンドポイントを使用してChromeドライバを取得してみます。
概要
今回作成したプログラムの流れは以下の通りです。
- レジストリからChromeのメジャーバージョンを取得
- JSON APIエンドポイントからChromeドライバのURLを取得
- Chromeドライバをダウンロードする
- ダウンロードファイルを解凍する
やってみた
前提としてWindows環境で作成しています。
プロジェクトの作成
Visual Studioから以下の手順でプロジェクトを作成しました。
「新しいプロジェクトの作成」を選択
⇒ 「コンソールアプリ」を選択
⇒ プロジェクト名を入力
⇒ フレームワークに「.Net 6.0」を選択 「最上位レベルのステートメントを使用しない」にチェック
プログラム
プログラムの詳しい説明については、コメントを参照してください。
なお、エラー処理などについてはお好みで調整してください。
using Microsoft.Win32;
using System.IO.Compression;
using System.Net.Http.Json;
using System.Runtime.Versioning;
namespace ChromeDriverDownload
{
internal class Program
{
// APIからのレスポンス定義
class ChromeJsonApi
{
public Dictionary<string, Milestone> Milestones { get; set; } = new();
}
class Milestone
{
public Dictionary<string, List<DownLoad>> Downloads { get; set; } = new();
}
class DownLoad
{
public string Platform { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
}
[SupportedOSPlatform("windows")]
static async Task Main()
{
var chromeVer = GetChromeMajorVer();
if (string.IsNullOrEmpty(chromeVer))
{
Console.WriteLine("Chromeバージョンの取得に失敗しました。");
return;
}
var url = await GetChromeDriverUrl(chromeVer, "win64");
if (string.IsNullOrEmpty(url))
{
Console.WriteLine("ChromeドライバのURL取得に失敗しました。");
return;
}
var downloadPath = @"C:\temp";
var downloadZipPath = await DownloadDriver(url, downloadPath);
if (string.IsNullOrEmpty(downloadZipPath))
{
Console.WriteLine("Chromeドライバのダウンロードに失敗しました。");
return;
}
ZipFile.ExtractToDirectory(downloadZipPath, downloadPath, true);
}
[SupportedOSPlatform("windows")]
// 自身のマシンのChromeメジャーバージョンを取得する
private static string? GetChromeMajorVer()
{
// レジストリを開く
// 「コンピューター\HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\BLBeacon」
using var regkey = Registry.CurrentUser.OpenSubKey(
@"SOFTWARE\Google\Chrome\BLBeacon");
if (regkey is null) return null;
// レジストリの値を取得
var chromeVer = regkey.GetValue("version") as string;
// 取得失敗
if (string.IsNullOrEmpty(chromeVer)) return null;
Console.WriteLine($"ChromeVer:{chromeVer}"); // 115.0.5790.111 など
// メジャーバージョンを取得
return chromeVer.Split('.')[0];
}
// ChromeドライバのURLを取得する
private static async Task<string?> GetChromeDriverUrl(
string chromeVer, string platform)
{
HttpClient client = new();
// JSON API endpointsを参照
var res = await client.GetAsync(
@"https://googlechromelabs.github.io/chrome-for-testing/latest-versions-per-milestone-with-downloads.json");
// APIアクセス失敗
if (!res.IsSuccessStatusCode) return null;
var json = await res.Content.ReadFromJsonAsync<ChromeJsonApi>();
if (json is null) return null;
// 対象のChromeバージョンを見つける
json.Milestones.TryGetValue(chromeVer, out var milestone);
if (milestone is null) return null;
// 対象バージョンのChromeドライバを見つける
milestone.Downloads.TryGetValue("chromedriver", out var download);
if (download is null) return null;
// 対象ドライバのプラットフォームを見つける
var winDownload = download.FirstOrDefault(x => x.Platform == platform);
if (winDownload is null) return null;
Console.WriteLine($"chromeDriverUrl:{winDownload.Url}");
return winDownload.Url;
}
// Chromeドライバをダウンロードする
private static async Task<string?> DownloadDriver(
string url, string downloadPath)
{
HttpClient client = new();
var res = await client.GetAsync(url);
if (!res.IsSuccessStatusCode) return null;
// ダウンロードファイルはZip
var downloadZipPath = $@"{downloadPath}\chromedriver.zip";
using var stream = await res.Content.ReadAsStreamAsync();
using var outStream = File.Create(downloadZipPath);
stream.CopyTo(outStream);
return downloadZipPath;
}
}
}
まとめ
JSON APIエンドポイントはいくつか種類があるので、要件に合うものを選択してください。
また突然のバージョンアップにより使えなくなるかもしれませんが、とりあえずは動くようになりました。そろそろPlaywrightで書き直さないといけないのかなぁ。
どなたかの参考になれば幸いです。
Discussion