2

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

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

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

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

4

2 回答 2

2

首先我应该说我暂时只支持 Chrome 和 Edge 驱动程序。但是,如果您可以继续,您也许可以添加自己对任何其他 SeleniumBasic 支持的 WebDrivers 的支持。

在我们开始之前,重要的是通过进入Tools > ReferencesVBE 来启用以下引用: 在此处输入图像描述

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

我决定把它做成一个类对象,因为我打算在未来做一些事情。您可以根据需要添加自己的属性和功能,但提供的代码仅允许更新 WebDrivers,至少目前如此。

这是完整的类模块代码:

Option Explicit

Rem Did Chrome change their file url and break your code?
' Check for an update: https://stackoverflow.com/a/67996166/5781745

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

现在您已经创建了 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

这样做的目的是为 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 损坏),请随时编辑此答案。

于 2021-06-16T04:00:58.173 回答
0

现在有一个 API 可以检查 ChromeDriver 的最新版本。所以代码可以变得更短。此外,仅当当前 chrome 版本与已安装的 chromedriver 版本不匹配时,才添加运行更新的功能。并使用管理员权限进行复制。我没有使用 Edge,因此我的代码中没有代码功能。

Function chkchromever()
Tempfolder = "D:\"
TempZipFile = Tempfolder & "Chromedriver.zip"
SeleniumFolder = Environ$("ProgramW6432") & "\SeleniumBasic\"
TempDrvFile = Tempfolder & "Chromedriver.exe"
'Delete chromedriver.exe from temporary folder if it already exists
If Dir(TempDrvFile) <> "" Then
    Kill (TempDrvFile)
End If


Dim oShell  As New WshShell
Dim objHttp As Object
Set objHttp = CreateObject("MSXML2.ServerXMLHTTP.6.0")

'Get chrome version
chrversion = CreateObject("WScript.Shell").RegRead("HKEY_CURRENT_USER\Software\Google\Chrome\BLBeacon\version")
dotsarr = Split(chrversion, ".")
leftchrver = dotsarr(0) & dotsarr(1)

'Get chromedriver version
gspath = Chr(34) & SeleniumFolder & "chromedriver.exe" & Chr(34)
torun = gspath & " --version"
errcode = oShell.Exec(torun).StdOut.ReadAll
verarr = Split(errcode, " ")
chrdrv = verarr(1)
dotsarr2 = Split(chrdrv, ".")
leftchrdrv = dotsarr(0) & dotsarr(1)

'If major version mismatch (first two numbers) then ask if update required
If leftchrver <> leftchrdrv Then
    myyn = MsgBox("Wrong version of chromedriver. " & vbCrLf & "Chrome version is " & chrversion & vbCrLf & "Chrome driver version is " & chrdrv, vbYesNo, "Do you want to update Chromedriver ?")
    If myyn = vbNo Then Exit Function
    'Get latest release version of chromedriver which matches installed version of Chrome
    url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" & dotsarr(0)
    Call objHttp.Open("GET", url, False)
    Call objHttp.send("")
    version_number = objHttp.responseText
    dotsarr3 = Split(version_number, ".")
    leftversion_no = dotsarr3(0) & dotsarr3(1)
    If leftchrver = leftversion_no Then
        'If chromedriver found then download it
        download_url = "https://chromedriver.storage.googleapis.com/" + version_number + "/chromedriver_win32.zip"
        Call objHttp.Open("GET", download_url, False)
        Call objHttp.send("")
        Set fileStream = New ADODB.Stream
        With fileStream
            .Open
            .Type = adTypeBinary
            .Write objHttp.responseBody
            .Position = 0
            .SaveToFile TempZipFile, adSaveCreateOverWrite
            .Close
        End With
        'Copy the new driver from .zip file to SeleniumBasic folder
        Set oApp = CreateObject("Shell.Application")
        oApp.Namespace(Tempfolder).CopyHere oApp.Namespace(TempZipFile).Items
        
        'Create batch file to copy chromedriver.exe to Seleniumbasic folder and run it using Administrator rights
        tmpbatpath = Tempfolder & "copychdrv.bat"
        'Check if Chromedriver downloaded successfully
        If Dir(TempDrvFile) <> "" Then
            Open tmpbatpath For Output As #1
            'Enable these if required to copy chromedriver.exe
            '        Print #1, "taskkill /f /im  GoogleCrashHandler.exe"
            '        Print #1, "taskkill /f /im  GoogleCrashHandler64.exe"
            '        Print #1, "taskkill /f /im  Chrome.exe"
            '        Print #1, "taskkill /f /im  Googleupdate.exe"
            If IsProcessRunning("Chromedriver.exe") Then
                Print #1, "taskkill /f /im  Chromedriver.exe"
            End If
            Print #1, "copy " & Chr(34) & TempDrvFile & Chr(34) & " " & Chr(34) & SeleniumFolder & "Chromedriver.exe" & Chr(34) & "/y"
            Close #1
            'copy it now by running batch file
            success = ShellExecute(0, "runas", tmpbatpath, aPic, vbNullString, SW_SHOWNORMAL)
        End If
        'Cleanup
        If Dir(TempZipFile) <> "" Then
            Kill (TempZipFile)
        End If
        If Dir(tmpbatpath) <> "" Then
            Kill (tmpbatpath)
        End If
    End If
End If
End Function
于 2021-07-27T13:44:56.843 回答