4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebDriver for Chromeの自動ダウンロード+更新

Last updated at Posted at 2022-10-21

概要

WebDriver for ChromeでRPAを利用していたら、ブラウザの自動更新が行われてしまった事で
エラーが発生してめんどくさかったのでダウンロード~更新までを自動化した。

VB.NET
Imports System.IO.Compression '参照設定 System.IO.Compression.FileSystem.dllとSystem.IO.Compression.dll
Imports Microsoft.Win32
Imports System.Net
Imports System.IO

    ''' <summary>
    ''' chromeWebDriverが古い場合はダウンロードして置き換える
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub updateChomeDriver()
        Dim zipPath As String = "C:\chrome_driver\chromedriver_win32.zip"
        Dim extractPath As String = "C:\chrome_driver"
        Dim strFileDrvVersion As String = ""

        If Not Directory.Exists(extractPath) Then
            Directory.CreateDirectory(extractPath)
        End If

        '現在インストールされているChromeブラウザバージョン取得
        Dim strChromeVer As String = GetChromeVersion()

        '現在インストールされているChromeWebDriverバージョン取得
        If IO.File.Exists(extractPath & "\chromedriver.exe") Then
            strFileDrvVersion = Runcmd("C:\chrome_driver\chromedriver.exe", "-v")
        Else
            strFileDrvVersion = ""
        End If

        '現在のChromeバージョンに見合ったDriverバージョンをサイトから調べる
        Dim siteVerURL As String = ""
        Using client As WebClient = New WebClient()
            siteVerURL = client.DownloadString("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + strChromeVer.Substring(0, strChromeVer.LastIndexOf(".")))
        End Using

        '現在のDriverバージョンとChromeブラウザバージョンを比較する
        If strFileDrvVersion = siteVerURL Then
            '同じならば処理しない
            Exit Sub
        End If

        'カレントディレクトリ設定
        Directory.SetCurrentDirectory("C:\chrome_driver")

        'ブラウザに合ったDriverバージョンをダウンロードする
        Using wc As New WebClient
            wc.DownloadFile("https://chromedriver.storage.googleapis.com/" + siteVerURL + "/chromedriver_win32.zip", "chromedriver_win32.zip")
        End Using

        'ZIP書庫を開く
        Using z As ZipArchive = ZipFile.OpenRead(zipPath)
            Dim za As ZipArchiveEntry = z.GetEntry("chromedriver.exe")
            If za Is Nothing Then
                '見つからなかった時
                Console.WriteLine("chromedriver_win32/chromedriver.exe が見つかりませんでした。")
            Else
                '2番目の引数をTrueにすると、上書きする
                za.ExtractToFile("C:\chrome_driver\chromedriver.exe", True)
                retMsg = "ChromeDriverを" & siteVerURL & "に更新しました。"
            End If
        End Using
    End Sub


    ''' <summary>
    ''' インストールされているChromeブラウザのバージョンを取得する
    ''' </summary>
    ''' <returns>バージョン文字列</returns>
    ''' <remarks></remarks>
    Private Function GetChromeVersion() As String
        Dim wowNode As String = String.Empty
        If Environment.Is64BitOperatingSystem Then wowNode = "Wow6432Node\"
        Dim regKey As RegistryKey = Registry.LocalMachine
        Dim keyPath As RegistryKey = regKey.OpenSubKey("Software\" + wowNode + "Google\Update\Clients")

        If IsDBNull(keyPath) Then
            regKey = Registry.CurrentUser
            keyPath = regKey.OpenSubKey("Software\" + wowNode + "Google\Update\Clients")
        End If

        If IsDBNull(keyPath) Then
            regKey = Registry.LocalMachine
            keyPath = regKey.OpenSubKey("Software\Google\Update\Clients")
        End If

        If IsDBNull(keyPath) Then
            regKey = Registry.CurrentUser
            keyPath = regKey.OpenSubKey("Software\Google\Update\Clients")
        End If

        If Not IsDBNull(keyPath) Then
            Dim subKeys As String() = keyPath.GetSubKeyNames()
            For Each subKey As String In subKeys
                Dim value = keyPath.OpenSubKey(subKey).GetValue("name")
                Dim found = False

                If Not IsDBNull(value) Then
                    found = value.ToString().Equals("Google Chrome", StringComparison.InvariantCultureIgnoreCase)
                End If

                If found Then
                    Return keyPath.OpenSubKey(subKey).GetValue("pv").ToString()
                End If
            Next
        End If

        Return "NotFound"
    End Function

    ''' <summary>
    ''' コマンドプロンプトでChromeDriverのバージョンを取得する
    ''' </summary>
    ''' <param name="chromeDriverPath"></param>
    ''' <param name="strcmd"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function Runcmd(chromeDriverPath As String, strcmd As String) As String
        'Processオブジェクト
        Dim proc As New System.Diagnostics.Process()

        With proc.StartInfo
            .FileName = chromeDriverPath

            '出力読取り可能化
            .UseShellExecute = False
            .RedirectStandardOutput = True
            .RedirectStandardInput = False

            'コマンドプロンプトのウィンドウ非表示
            .CreateNoWindow = True

            'コマンド(/c:コマンド実行後、コマンドを実行したcmd.exeを終了)
            .Arguments = "/c " & strcmd
        End With

        'コマンド実行
        proc.Start()

        '実行結果取得
        Dim result As String = proc.StandardOutput.ReadToEnd()

        proc.WaitForExit()
        proc.Close()

        Dim res As String() = result.Split(" ")

        Return res(1)

    End Function

Chromeブラウザの自動アップデート停止

ChromeDriverのLATEST_RELEASEが記載されているサイトの更新が行われなくなったので、
Chromeブラウザの自動アップデートを停止して手動対応する事にした。

【手順】

①GoogleUpdateAdmx管理用テンプレートをダウンロードする。
https://dl.google.com/update2/enterprise/googleupdateadmx.zip

②C:\Windows\PolicyDefinitionsへコピーする
解凍したgoogle.adml ファイルと GoogleUpdate.adml ファイルをC:\Windows\PolicyDefinitionsルートへコピー。
解凍したen-USフォルダの中身をC:\Windows\PolicyDefinitions\en-USフォルダへコピーする。

③コマンドプロンプトでgpedit.mscを起動する。
グループ ポリシー([コンピューターの構成] フォルダ)で次のように操作する。
[Google] ⇒ [Google Update] ⇒ [Applications] ⇒[GoogleChrome] に移動する。
[Update policy override] をオンにする。
[Options] で [Disable updates] にする。

④動作チェック
ブラウザのヘルプの[Chrome について] をクリックして、
「管理者が更新を無効にした」旨のメッセージが出ていれば効いている。

上述の手順で自動アップデートが行われなくなるので、
タイミングを見計らって手動でブラウザ更新とchromedriver.exe更新を行います。

chromeDriverの最新exeは以下のサイトに掲載されています。
https://googlechromelabs.github.io/chrome-for-testing/#stable

また、chromeブラウザの向こう3バージョンのリリースロードマップが
以下のサイトに掲載されています。
https://chromestatus.com/roadmap

その後

すっかりほったらかしになっていた本件だが、ChromeDriverのダウンロードURLが取得できるAPIが公開されていたので再度自動化にトライしてみた。

とりあえず以下のChromeDriverFinder.vbをプロジェクトに追加する。

VB.NET
Imports System.IO
Imports System.Net.Http
Imports Newtonsoft.Json

' JSONのルートオブジェクトに対応
Public Class ChromeVersionsInfo
    <JsonProperty("timestamp")>
    Public Property Timestamp As String

    <JsonProperty("versions")>
    Public Property Versions As List(Of VersionDetail)
End Class

' 各バージョンの詳細情報
Public Class VersionDetail
    <JsonProperty("version")>
    Public Property Version As String

    <JsonProperty("revision")>
    Public Property Revision As String

    <JsonProperty("downloads")>
    Public Property Downloads As Downloads
End Class

' ダウンロード可能なファイルのカテゴリ
Public Class Downloads
    <JsonProperty("chrome")>
    Public Property Chrome As List(Of DownloadItem)

    <JsonProperty("chromedriver")>
    Public Property ChromeDriver As List(Of DownloadItem)
End Class

' 各ダウンロードファイルの情報
Public Class DownloadItem
    <JsonProperty("platform")>
    Public Property Platform As String

    <JsonProperty("url")>
    Public Property Url As String
End Class


Public Class ChromeDriverFinder
    Private Const ApiEndpoint As String = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"

    ''' <summary>
    ''' 指定されたChromeバージョンに一致、または最も近い過去のバージョンのChromeDriverのダウンロードURLを取得します。
    ''' </summary>
    ''' <param name="targetVersionString">検索するChromeのバージョン (例: "142.0.7444.163")</param>
    ''' <param name="targetPlatform">プラットフォーム (例: "win64", "win32", "mac-x64", "mac-arm64", "linux64")</param>
    ''' <returns>ダウンロードURL。見つからない場合は空の文字列を返します。</returns>
    Public Shared Async Function GetChromeDriverUrlAsync(targetVersionString As String, targetPlatform As String) As Task(Of String)
        Try
            Using client As New HttpClient()
                Dim jsonString As String = Await client.GetStringAsync(ApiEndpoint)
                Dim chromeInfo As ChromeVersionsInfo = JsonConvert.DeserializeObject(Of ChromeVersionsInfo)(jsonString)

                Dim targetVersionDetail As VersionDetail = Nothing

                ' 1. まずは完全一致を探す
                targetVersionDetail = chromeInfo.Versions.FirstOrDefault(Function(v) v.Version = targetVersionString)

                ' 2. 完全一致がない場合、最も近い過去のバージョンを探す
                If targetVersionDetail Is Nothing Then
                    Dim targetVersion As Version = Nothing
                    ' 入力されたバージョン文字列をVersionオブジェクトに変換
                    If Version.TryParse(targetVersionString, targetVersion) Then

                        ' 条件に合うバージョンを絞り込む
                        '   - メジャーバージョンが同じ
                        '   - 指定バージョン以下である
                        '   - その中で降順に並び替え、最初のもの(=最も近い)を取得
                        targetVersionDetail = chromeInfo.Versions.
                            Select(Function(v)
                                       ' リスト内の各バージョンもVersionオブジェクトに変換しておく
                                       Dim currentVersion As Version = Nothing
                                       Version.TryParse(v.Version, currentVersion)
                                       Return New With {Key .Detail = v, Key .VersionObject = currentVersion}
                                   End Function).
                            Where(Function(x) x.VersionObject IsNot Nothing AndAlso
                                              x.VersionObject.Major = targetVersion.Major AndAlso
                                              x.VersionObject <= targetVersion).
                            OrderByDescending(Function(x) x.VersionObject).
                            Select(Function(x) x.Detail).
                            FirstOrDefault()
                    End If
                End If

                ' 3. 見つかったバージョンの詳細からURLを取得
                If targetVersionDetail IsNot Nothing Then
                    Dim chromedriverDownload As DownloadItem = targetVersionDetail.Downloads.ChromeDriver.FirstOrDefault(Function(d) d.Platform = targetPlatform)

                    If chromedriverDownload IsNot Nothing Then
                        ' 見つかったバージョン番号も一緒に返すようにすると、どのバージョンが選択されたか分かりやすい
                        ' Console.WriteLine($"選択されたバージョン: {targetVersionDetail.Version}")
                        Return chromedriverDownload.Url
                    End If
                End If
            End Using
        Catch ex As Exception
            Console.WriteLine($"エラーが発生しました: {ex.Message}")
        End Try

        Return String.Empty
    End Function

    ''' <summary>
    ''' PCにインストールされているGoogle Chromeのバージョンを取得します。
    ''' </summary>
    ''' <returns>バージョンの文字列 (例: "125.0.6422.112")。見つからない場合は空の文字列を返します。</returns>
    Public Shared Function GetInstalledChromeVersion(chromePath As String) As String
        ' 1. レジストリなどからchrome.exeのフルパスを取得する
        'Dim chromePath As String = GetChromeExecutablePath()

        ' パスが見つからない、またはその場所にファイルが存在しない場合は終了
        If String.IsNullOrEmpty(chromePath) OrElse Not File.Exists(chromePath) Then
            Return String.Empty
        End If

        ' 2. 実行ファイルのバージョン情報を取得する
        Try
            Dim versionInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(chromePath)
            Return versionInfo.FileVersion
        Catch ex As Exception
            ' 何らかの理由でバージョン情報を取得できなかった場合
            Console.WriteLine($"Chromeのバージョン情報取得に失敗しました: {ex.Message}")
            Return String.Empty
        End Try
    End Function

End Class

呼び出し側はこんな感じです。

VB.NET
' --- 1. chromeWebDriverのバージョン確認&更新
Dim chormePath As String = "C:\Program Files\Google\Chrome\Application\chrome.exe"
Dim chromeVersion As String = ""          '142.0.7444.163など
Dim platform As String = "win64"          ' "win32", "mac-arm64" など環境に合わせて変更

chromeVersion = ChromeDriverFinder.GetInstalledChromeVersion(chormePath)

' URLを非同期で取得
Dim downloadUrl As String = Await ChromeDriverFinder.GetChromeDriverUrlAsync(chromeVersion, platform)


' --- 2. ファイルのダウンロード ---
' 保存先フォルダとファイル名を指定
Dim tempFolder As String = Path.GetTempPath() ' 一時フォルダに保存
Dim zipFileName As String = "chromedriver.zip"
Dim zipFilePath As String = Path.Combine(tempFolder, zipFileName)

Try
    Using client As New HttpClient()
        Dim fileBytes As Byte() = Await client.GetByteArrayAsync(downloadUrl)
        File.WriteAllBytes(zipFilePath, fileBytes)
        MessageBox.Show($"ZIPファイルをダウンロードしました: {zipFilePath}")
    End Using
Catch ex As Exception
    MessageBox.Show($"ファイルのダウンロード中にエラーが発生しました: {ex.Message}")
    Return
End Try

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?