はじめに
ブラウザ自動テストのデファクトスタンダードであるSelenium
。
悩ましいことに操作対象のブラウザのバージョンに合わせてWebDriver
を更新しなければいけません。
今回対象とするブラウザはGoogle Chrome
とChromium版Edge
です。
いずれも約4週間に一度のペースで自動更新されるため、「自動更新しよう!」ということになります。
chromedriver
の更新方法と、msedgedriver
の更新方法をまとめました。
2023/09月 v116 以降の chromedriver の公開URLが変更されたため、記事の内容を修正しました。
実装方針
それぞれのWebDriver
のバージョン情報やバイナリを取得できるWebAPIが公開されています。
それを組み合わせることで自動更新を実現します。
詳細はそれぞれ以下のパスを参照してください:
上記URLをみればわかる通り、やりたいことに合わせて色々アレンジできそうです。
※注意:以下、WindowsOS用のWin64バイナリを取得している例なので、適宜アレンジが必要です。
chromedriver.exe
-
操作対象となる
chrome.exe
のメジャーバージョンを取得する
Windowsだったらこのパスにあるはず:C:\Program Files\Google\Chrome\Application\chrome.exe -
以下のURIによって、メジャーバージョンをもとに最新の
WebDriver
のフルバージョンを取得する
※例えば v116 の場合:
https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_116
※注意)以下のURIは v115 以降は無効です:
https://chromedriver.storage.googleapis.com/LATEST_RELEASE_114 -
以下のURIによって、
WebDriver
のフルバージョンをもとにzipファイルをダウンロードする
※例えば 116.0.5845.96 の場合:
https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/116.0.5845.96/win64/chromedriver-win64.zip
※注意)以下のURIは v115 以降は無効です:
https://chromedriver.storage.googleapis.com/114.0.5735.90/chromedriver_win32.zip -
ダウンロードしたzipファイルを展開する
msedgedriver.exe
-
操作対象となる
msedge.exe
のメジャーバージョンを取得する
Windowsだったらこのパスにあるはず:C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe -
以下のURIによって、メジャーバージョンをもとに最新の
WebDriver
のフルバージョンを取得する
※例えば v116 の場合:
https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/LATEST_RELEASE_116 -
以下のURIによって、
WebDriver
のフルバージョンをもとにzipファイルをダウンロードする
※例えば 116.0.1938.69 の場合:
https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/116.0.1938.69/edgedriver_win64.zip -
ダウンロードしたzipファイルを展開する
実装例(C#)
C#
で実装するとしたらこんな感じです。
注意:msedgedriver
のバージョン取得結果の末尾に改行が入ってしまうのでトリミング処理が必要です。
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal class Program
{
private static async Task Main(string[] args)
{
await UpdateChromeDriverAsync();
await UpdateMsEdgeDriver();
}
public static async Task UpdateChromeDriverAsync()
{
// exeを配置したいフォルダを指定
var directory = "chromedriver_" + Guid.NewGuid().ToString();
var path = @"C:\Program Files\Google\Chrome\Application\chrome.exe";
var majorversion = FileVersionInfo.GetVersionInfo(path).FileMajorPart;
var versionUri = new Uri($@"https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_{majorversion}");
var version = await GetResponseAsStringAsync(versionUri);
var driverUri = new Uri($@"https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/{version}/win64/chromedriver-win64.zip");
await DownloadAsync(driverUri, directory);
}
public static async Task UpdateMsEdgeDriver()
{
// exeを配置したいフォルダを指定
var directory = "msedgedriver_" + Guid.NewGuid().ToString();
var path = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";
var majorversion = FileVersionInfo.GetVersionInfo(path).FileMajorPart;
var versionUri = new Uri($@"https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/LATEST_RELEASE_{majorversion}");
var version = await GetResponseAsStringAsync(versionUri);
// 末尾に改行コードが入ってしまうので削除する
version = version.Trim();
var driverUri = new Uri($@"https://msedgewebdriverstorage.blob.core.windows.net/edgewebdriver/{version}/edgedriver_win64.zip");
await DownloadAsync(driverUri, directory);
}
private static async Task<string> GetResponseAsStringAsync(Uri uri)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
using (var httpClient = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
using (var content = response.Content)
{
return await content.ReadAsStringAsync();
}
}
}
private static async Task DownloadAsync(Uri uri, string extractDirectory)
{
if (!Directory.Exists(extractDirectory))
{
_ = Directory.CreateDirectory(extractDirectory);
}
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
using (var httpClient = new HttpClient())
using (var request = new HttpRequestMessage(HttpMethod.Get, uri))
using (var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
using (var content = response.Content)
using (var stream = await content.ReadAsStreamAsync())
using (var archive = new ZipArchive(stream))
{
UnZip(extractDirectory, archive);
}
}
private static void UnZip(string extractDirectory, ZipArchive archive)
{
foreach (var entry in archive.Entries.Where(x => Path.GetExtension(x.Name) == ".exe"))
{
var path = Path.GetFullPath(Path.Combine(extractDirectory, Path.GetFileName(entry.FullName)));
using (var stream = entry.Open())
using (var writer = new FileStream(path, FileMode.Create, FileAccess.Write))
{
var buffer = new byte[2048];
int len;
while ((len = stream.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, len);
}
}
}
}
}
}
ブラウザパスの取得について
ブラウザがインストールされいているパスが環境によって異なることがあります。
そのため、更新ロジックのバージョン取得の部分が適切に動作しないことがあります。
その対策として、PATH でブラウザ指定してヘッドレスモードで一度起動し、
そのプロセスからファイルパスを取得する方法を提示します。
私はこの手法で driver を安定して更新することができています。
public static class BrowserFile
{
public static string GetChromePath()
{
return GetPath("chrome");
}
public static string GetMsedgePath()
{
return GetPath("msedge");
}
private static string GetPath(string cmd)
{
try
{
string path;
using (var p = Process.Start(cmd, "--headless"))
{
_ = p.WaitForInputIdle();
path = p.MainModule.FileName;
p.Kill();
}
return path;
}
catch
{
return null;
}
}
}
おわりに
同じ目的の記事がたくさんありましたが、
本質的なところを端的にまとめている記事がなかったので、本質的なところを端的にまとめてみました。
また、今後需要が伸びてくるであろうmsedgedriver
にも言及し、競合記事との差別化を図りました。