selenium 如何在VBA中自动更新Chrome驱动程序或EdgeDriver?

6ljaweal  于 2023-01-13  发布在  其他
关注(0)|答案(4)|浏览(418)

我已经在网上搜索了一个解决方案来自动“自动更新”我的SeleniumEdgeDriver。对于那些使用SeleniumBasic的人来说,你知道当你的主主机浏览器得到一个重大更新时,经常从相应的网页手动下载驱动程序会很麻烦。
在我的网络搜索中,我发现支持其他语言“自动更新”这些驱动程序的版本,但VBA,像往常一样,缺乏支持。
现在我不认为这是完美的解决方案,但它至少是有效的。我能看到的问题是,在未来的每个网页的布局可能会改变,所以我欢迎更新,如果是这样的话,我会尝试更新。但在大多数情况下,它应该只是工作。
虽然这是一个自我回答的问题,但我绝对希望看到其他方法张贴在这里,供我自己和其他用户尝试。SeleniumBasic是某些应用程序的好工具,但通常缺乏社区支持,因为VBA在社区中的使用不如其他语言广泛-至少没有在更复杂的水平上。

b5buobof

b5buobof1#

  • 我应该先说我目前只支持Chrome和Edge驱动程序,但如果你能沿着,你也许可以添加你自己对任何其他SeleniumBasic支持的WebDrivers的支持。*

在开始之前,请务必在VBE中转到Tools〉References启用以下References:

接下来,您需要创建一个名为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类,您可以在标准模块中使用它,例如:

  • 重要提示:我不确定在您更新Web浏览器和驱动程序正式发布之间是否有延迟,因此在更新驱动程序之前,我会放一些错误处理,看看Selenium是否先抛出错误,如果驱动程序与浏览器版本不匹配,Selenium将抛出错误# 33,如果您检查此错误,此时您可以安全地继续更新WebDriver。2我们要防止的是在浏览器自动更新之前更新驱动程序,从而导致版本不匹配。3 *
  • 也有可能您的浏览器可能会更新,而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的Temp文件夹。
下载完文件后,我们继续调用ExtractZipAndCopy例程。这只是将.exe文件解压缩到Selenium文件夹,首先删除旧文件。Edge会做一些额外的维护工作,但现在基本上已经更新了!
我希望这能帮助那些因为我不得不定期更新这些驱动程序而感到恼火的人,并且希望得到一个自动化的解决方案。如果需要进行微小的更改,例如URL损坏,请随时edit此答案。

11dmarpk

11dmarpk2#

现在有一个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
ulydmbyx

ulydmbyx3#

由于我使用的是公司PC,因此我更新了代码,以便在锁定的PC上工作

Option Explicit
'**********************************************************
' PUBLIC FUNCTION
'/
'**********************************************************
' @Fn       chkchromever
'
' @brief    Check if Selenium Crome Driver is up to date or update it
'
' @param    checks Crome version and Installed and availible Driver for Selenium
'
' @SUBs     IsProcessRunning, ShellExecute
'
' Librarys  Selenium Type library
'           Windows Script Host Object Model            - Dim oShell  As New WshShell ,
'           Microsoft ActiveX Data Objects 6.1 Library  - Set fileStream = New ADODB.Stream
'
' @return   new driver
'/

Public Declare Function ShellExecute _
    Lib "shell32.dll" _
        Alias "ShellExecuteA" ( _
            ByVal Hwnd As Long, _
            ByVal lpOperation As String, _
            ByVal lpFile As String, _
            ByVal lpParameters As String, _
            ByVal lpDirectory As String, _
            ByVal nShowCmd As Long) _
As Long

Function chkchromever()
Dim tempfolder As Variant, TempZipFile As Variant
Dim SeleniumFolder As String, TempDrvFile As String
Dim chrversion As String, leftchrver As String
Dim dotsarr() As String
Dim gspath As String, torun As String, errcode As String
Dim verarr() As String, chrdrv As String, leftchrdrv As String
Dim dotsarr2() As String
Dim myyn As Integer
Dim Url As String, version_number As String, leftversion_no As String
Dim dotsarr3() As String
Dim download_url As String

tempfolder = "C:\Temp\"
TempZipFile = tempfolder & "Chromedriver.zip"
'SeleniumFolder = Environ$("ProgramW6432") & "\SeleniumBasic\"
SeleniumFolder = Environ$("LOCALAPPDATA") & "\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) ' chr34 er gåseøjne
torun = gspath & " --version"
errcode = oShell.Exec(torun).StdOut.ReadAll
verarr = Split(errcode, " ")
chrdrv = verarr(1)
dotsarr2 = Split(chrdrv, ".")
leftchrdrv = dotsarr2(0) & dotsarr2(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("")
        Dim fileStream As Object
        Set fileStream = New ADODB.Stream
        With fileStream
            .Open
            .Type = adTypeBinary
            .Write objHttp.responseBody
            .Position = 0
            .SaveToFile TempZipFile, adSaveCreateOverWrite
            .Close
        End With
        'unzip file
        Dim oApp As Object
        Set oApp = CreateObject("Shell.Application")
        oApp.Namespace(tempfolder).CopyHere oApp.Namespace(TempZipFile).Items
        'Check if Chromedriver downloaded successfully
        If Dir(TempDrvFile) <> "" Then
            If IsProcessRunning("Chromedriver.exe") Then
               Shell "cmd /c""" & "taskkill /f /im  Chromedriver.exe"
            End If
            'Copy / Overwrite file in SeleniumBasic folder
            FileCopy TempDrvFile, SeleniumFolder & "Chromedriver.exe"
        End If
        'Cleanup
        If Dir(TempZipFile) <> "" Then
            Kill (TempZipFile)
        End If
        If Dir(TempDrvFile) <> "" Then
            Kill (TempDrvFile)
        End If
    End If
End If
End Function

Function IsProcessRunning(process As String)
    Dim objList As Object
    
    Set objList = GetObject("winmgmts:") _
        .ExecQuery("select * from win32_process where name='" & process & "'")
    
    IsProcessRunning = objList.Count > 0
End Function
yfwxisqw

yfwxisqw4#

我不得不修改上面由Jesper Martin Schumacher发布的代码,因为我们的IT部门已经将所有Office应用程序更新为64位。
该代码在“New”关键字的示例上失败,所以我研究并发现:
compile error User-defined type not defined at "oShell As WshShell"
建议使用“后期绑定”CreateObject方法,如下所示。

Set oShell = CreateObject("WScript.Shell") 'Had to edit this line. It WAS "Set oShell = New WshShell"

Set fileStream = CreateObject("ADODB.Stream") 'Had to edit this line. It WAS "Set fileStream = New ADODB.Stream"

相关问题