如何在 VBA 中自动更新 ChromeDriver 或 EdgeDriver?

K.D*_*ᴠɪs 6 selenium vba selenium-chromedriver selenium-webdriver selenium-edgedriver

我在网上搜索了自动“自动更新”我的 Selenium EdgeDriver 的解决方案。对于那些使用 SeleniumBasic 的人来说,您知道当您的主主机浏览器进行重大更新时,经常从相应的网页手动下载驱动程序可能会很麻烦。

在我的网络搜索中,我发现其他语言支持“自动更新”这些驱动程序的版本,但 VBA 一如既往地缺乏支持。

现在我并不认为这是完美的解决方案,但它至少有效。我将来看到的问题是每个网页的布局可能会发生变化,所以如果是这种情况我欢迎更新,我也会尝试更新。但在大多数情况下,它应该可以工作。

虽然这是一个自我回答的问题,但我绝对希望看到此处发布的其他方法供我自己和其他用户尝试。SeleniumBasic 对于某些应用程序来说是一个很好的工具,但通常缺乏社区支持,因为 VBA 在社区中的使用不像其他语言那样广泛 - 至少在更复杂的层面上如此。

K.D*_*ᴠɪs 5

首先我应该说我暂时只支持 Chrome 和 Edge 驱动程序。但如果您能够继续操作,您也许能够为任何其他 SeleniumBasic 支持的 WebDriver 添加您自己的支持。

Tools > References在我们开始之前,通过进入 VBE 来启用以下引用非常重要:在此输入图像描述

接下来,您需要创建一个名为SeleniumWebDriver的类模块
在此输入图像描述

我决定将其设为类对象,因为我打算将来在它的基础上进行一些构建。您可以根据需要添加自己的属性和函数,但所提供的代码仅允许更新 WebDrivers,至少目前如此。

这是完整的类模块代码:

Option Explicit

Rem Did Chrome change their file url and break your code?
' Check for an update: /sf/answers/4759731651/

Private ChromeDriver As Selenium.ChromeDriver
Private EdgeDriver As Selenium.EdgeDriver
Private SeleniumFolder As String
Private TempZipFile As String
Private ChromeInit As Boolean, EdgeInit As Boolean

Public Enum dType
    Chrome
    Edge
End Enum

Public Property Get SeleniumFolderPath() As String
    SeleniumFolderPath = SeleniumFolder
End Property

Public Property Let SeleniumFolderPath(ByVal FolderPath As String)
    SeleniumFolder = FolderPath
End Property
    
Public Sub UpdateDriver(ByVal DriverType As dType)

    'URLs to the drivers' home pages to which we can grab the curr versions
    Dim URLPath As String
    Select Case DriverType
    Case dType.Chrome
        URLPath = "https://chromedriver.chromium.org/home"
    Case dType.Edge
        URLPath = "https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/"
    End Select
    
    'Grab the current Version # from the driver's webpage
    Dim Doc As New HTMLDocument, DriverVer As String
    With New MSXML2.XMLHTTP60
        .Open "GET", URLPath
        .send
        Doc.body.innerHTML = .responseText
    End With
    DriverVer = getCurrentVersion(Doc, DriverType)
    
    DownloadUpdatedDriver DriverVer, DriverType
    ExtractZipAndCopy DriverType

End Sub

' For use in a later project. Not needed at this time
Private Sub InitializeDriver(ByVal DriverType As dType)
    Select Case DriverType
    Case dType.Chrome
        Set ChromeDriver = New Selenium.ChromeDriver
        ChromeDriver.Start
        ChromeInit = True
    Case dType.Edge
        Set EdgeDriver = New Selenium.EdgeDriver
        EdgeDriver.Start
        EdgeInit = True
    End Select
End Sub

Private Function getCurrentVersion(Doc As HTMLDocument, DriverType As dType) As String

    Dim div As HTMLDivElement

    Select Case DriverType
    Case dType.Chrome
        For Each div In Doc.getElementsByTagName("p")
            If div.innerText Like "Latest stable release*" Then
                With New VBScript_RegExp_55.RegExp
                    .Pattern = "ChromeDriver\s([\d\.]+)\b"
                    getCurrentVersion = .Execute(div.innerText)(0).SubMatches(0)
                    Exit Function
                End With
            End If
        Next
    Case dType.Edge
        With New VBScript_RegExp_55.RegExp
            .Pattern = "Version:\s([\d\.]+)"
            For Each div In Doc.getElementsByClassName("module")(0).getElementsByTagName("p")
                If .test(div.innerText) Then
                    getCurrentVersion = .Execute(div.innerText)(0).SubMatches(0)
                    Exit Function
                End If
            Next
        End With
    End Select

End Function

Private Sub DownloadUpdatedDriver(ByVal CurrVersion As String, DriverType As dType)
    
    Dim URLPath As String
    Select Case DriverType
    Case dType.Chrome
        URLPath = "https://chromedriver.storage.googleapis.com/" & CurrVersion & "/chromedriver_win32.zip"
    Case dType.Edge
        Kill Environ$("LocalAppData") & "\SeleniumBasic\Driver_Notes\*.*"
        URLPath = "https://msedgedriver.azureedge.net/" & CurrVersion & "/edgedriver_win64.zip"
    End Select
    
    Dim FileStream As New ADODB.Stream
    With New MSXML2.XMLHTTP60
        .Open "GET", URLPath
        .send
        FileStream.Open
        FileStream.Type = adTypeBinary
        FileStream.Write .responseBody
        FileStream.SaveToFile TempZipFile, adSaveCreateOverWrite
        FileStream.Close
    End With
    
End Sub

Private Sub ExtractZipAndCopy(ByVal DriverType As dType)

    Dim FileName As String
    Select Case DriverType
    Case dType.Chrome: FileName = "\chromedriver.exe"
    Case dType.Edge: FileName = "\edgedriver.exe"
    End Select

    'Delete the old WebDriver
    Kill SeleniumFolder & FileName
    
    'Copy the new driver from .zip file to SeleniumBasic folder
    Dim oShell As New shell
    oShell.Namespace(SeleniumFolder).CopyHere oShell.Namespace(TempZipFile).Items
    
    'Selenium VBA expects 'edgedriver' for edge, but new drivers are named 'msedgedriver'.
    'If we are updating Edge, we need to rename the file
    If DriverType = dType.Edge Then
        Name SeleniumFolder & "msedgedriver.exe" As SeleniumFolder & "edgedriver.exe"
    End If
        
    'Delete the temporary zip file
    Kill TempZipFile

End Sub

Private Sub Class_Initialize()

    ' Set the default file path. Can be modified later using ChromeDriverPath property
    SeleniumFolder = Environ$("LocalAppData") & "\SeleniumBasic\"
    TempZipFile = Environ$("LocalAppData") & "\Temp\WebDriver.zip"

End Sub
Run Code Online (Sandbox Code Playgroud)

现在您已经创建了 Selenium 类,现在可以在标准模块中使用它,例如: 在此输入图像描述

重要提示:我不确定您更新网络浏览器和驱动程序正式发布之间是否存在延迟。因此,在更新驱动程序之前,我会进行一些错误处理,以查看 Selenium 是否首先抛出错误。如果驱动程序与浏览器版本不匹配,Selenium 将抛出错误#33。如果您检查此错误,此时您应该可以安全地继续更新 WebDriver。我们要防止的是您在浏览器自动更新之前更新驱动程序,从而导致版本不匹配。

也有可能您的浏览器可能会更新,而 Selenium 驱动程序尚未发布 - 但不幸的是,这不是我们可以控制的。


这个答案的其余部分将详细介绍它正在做什么。如果你不介意的话,你现在就可以离开了。

首先,与任何其他对象一样,我们必须初始化它。在上面的例子中,我们用With New SeleniumWebDriver语句来做到这一点。这会Class_Initialize()在这里触发事件:

Private Sub Class_Initialize()

    ' Set the default file path. Can be modified later using ChromeDriverPath property
    SeleniumFolder = Environ$("LocalAppData") & "\SeleniumBasic\"
    TempZipFile = Environ$("LocalAppData") & "\Temp\WebDriver.zip"

End Sub
Run Code Online (Sandbox Code Playgroud)

这样做的目的是设置 SeleniumBasic 文件夹和临时文件的默认文件路径。但是,如果您的文件夹位于其他位置,则此类有一个属性,您可以手动更改文件夹。只需使用该属性来建立您的新路径即可。ClassObj.SeleniumFolderPath()

TempZipFile是一个类范围的变量,将存储您从相应网站下载的 .zip 文件。

调用该UpdateDriver方法后,该类将向相应驱动程序的网页发出GET请求,然后从该页面获取当前版本#。然后,它将将此驱动程序版本传递给例程DownloadUpdatedDriver,该例程存储每个相应驱动程序的下载链接。对于 Chrome,链接为:https://chromedriver.storage.googleapis.com/<Version#>/chromedriver_win32.zip,对于 Edge 为:https://msedgedriver.azureedge.net/<Version#>/edgedriver_win64.zip。重要的是要认识到,如果您碰巧使用 32 位版本的 Edge,则需要将 URL 更改为edgedriver_win32.zip. 此例程将 .zip 文件下载到本地 AppData 的临时文件夹。

下载文件后,我们继续调用例程ExtractZipAndCopy。这只是将 .exe 文件提取到 Selenium 文件夹,首先删除旧文件。Edge 做了一些额外的维护工作,但您现在基本上已经更新了!

我希望这可以帮助那些因我必须定期更新这些驱动程序并想要一个自动化解决方案而烦恼的人。如果需要进行细微更改(例如 URL 损坏),请随时编辑此答案。