VBA用の自作関数(Selenium)

本ページはプロモーションが含まれています

モジュールは一番最後に全部まとめたものを貼っています

SeleniumBasicを使う上で「こんな機能・関数があったら便利なのにな~」ってのを作りました

実際に自分でSeleniumBasicを使ったツールを作る時は必ず入れて不定期アップデートしているので適当なタイミングで見に来てください

SeleniumOpen

Akamaiが比較的有名なキーワードですがSeleniumが使えないサイトがあって、その対応で作ったSelenium起動関数

具体的にはなぜかログイン処理などが永遠と終わらないサイトとかに使えない場合に使える他、Chromeがバージョン100になってなぜかエラーになりがちなGetでページ遷移も比較的安定する気がする

SeleniumClose

「SeleniumOpen」とセット

ソースを見ればわかる、単純にドライバを落とした後に一時プロファイルフォルダも削除するだけ


ここから先の「○○と○○Elm」は要素の指定の仕方が違うだけで動きは同じ
※結局○○Elmの方を実行することになるので

ViewCheckとViewCheckElm

画面上の要素の有無を確認する関数

引数でモード分けしていてソース上に存在しているか、画面上に見えているか、活性化しているかの3段階で判定できるようにしている

以降の関数も同じことを前処理に入れているのでこれだけで使うことは多分少ない

InputTextとInputTextElm

Seleniumの文字入力は「SendKeys」の追記型なので一度クリアしてあげる処理やJavaScriptで活性化処理が入るページのために活性化待ちしたりする処理を入れている

後はカーソルアウトすると発火するJavaScriptが仕込んであるページも良く見かけるのでTabキーを押してカーソルアウトしてあげる親切設計

InputTextScript

どんな理屈かまで調べてないけどなぜか「Clear」コマンドが効かないInputがあって、↑の「InputText」では思い通りの動きにならないのでやむを得ずJavaScriptで強制更新するやつ

多分レアケースなのでわざわざ関数にしなくても個別対応でいいじゃんと思いつつ、入力前の活性化チェックや入力後のカーソルアウトをしたいから関数にした

GetTextとGetTextElm

GetTextと言いつつValueとかタグ内の情報を取得できるようにAttributeも見るように作った

よくあるケースはaタグのhrefからリンク先URLを取ったり、data-○○とかに入ってる情報を取りたいことがあるので意外と便利

ButtonClickとButtonClickElm

クリックする手前で他の関数と同じようにチェックする以外はただクリックするだけ

ChromeDriverVersionCheck

これが一番大事

結論から言うとChromeDriverを自動更新する関数

Pythonにあるモジュールを解析してVBA用にアレンジを加えていて、最初にこの関数を呼び出すだけでバージョン不一致エラーのイライラから解放される

特にツールを提供する時に

Chromeのバージョンが上がったらChromeDriverのバージョンも上げないと行けなくて、このサイトからダウンロードしてそれをこのフォルダにコピーして・・・

とか説明面倒だしリテラシー低い人だと伝わらないしってことがあるのでわかってくれる人には感動レベル(なはず)

実際のモジュール

'モジュール名は「SeleniumAssistance」で登録してください
Option Explicit
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
Private Declare PtrSafe Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" _
                         (ByVal lpApplicationName As String, _
                          ByVal lpKeyName As Any, _
                          ByVal lpDefault As String, _
                          ByVal lpReturnedString As String, _
                          ByVal nSize As Long, _
                          ByVal lpFileName As String) As Long
                           
Private Declare PtrSafe Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" _
                         (ByVal lpApplicationName As String, _
                          ByVal lpKeyName As Any, _
                          ByVal lpString As Any, _
                          ByVal lpFileName As String) As Long
                           
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
                        (ByVal pCaller As Long, _
                         ByVal szURL As String, _
                         ByVal szFileName As String, _
                         ByVal dwReserved As Long, _
                         ByVal lpfnCB As Long) As Long
 
Private Const ConfigFile As String = "config.ini"
Private Const SecName As String = "ChromeDriver" '---セクション名
Private Const KeyName As String = "ChromeVersion" '---キー名
Private Const Default As String = "1.0.0.0" '---デフォルト値

Private Type VersionClass '---本当はクラスオブジェクトにしたいけどこれだけのためにモジュール作りたくない
    Major As Long
    Minor As Long
    Build As Long
    Revision As Long
    strVersion As String
End Type

Private i As Long
Private pathArr As Variant
Private RtnCD As Long
Private RtnStr As String
 
Private intFF As Long
Private strUrl As String
 
Private ChromeVersion As VersionClass
Private ChromePath As String '---Chrome.exeが保存されているパス
Private ChromeDriverVersion As VersionClass
Private ChromeDriverPath As String '---ChromeDriverが保存されているパス
Private NewDriverVersion As String
 
Private objFso As Object ' Scripting.FileSystemObject '--- 「Microsoft Scripting Runtime」の参照設定
Private objFolder As Object 'Scripting.Folder
Private objRE As Object ' RegExp '--- 「Microsoft VBScript Regular Expressions 5.5」の参照設定
Private xmlhttp As Object ' MSXML2.XMLHTTP60 '--- 「Microsoft XML v6.0」の参照設定
Private htmlDoc As Object 'HTMLDocument '--- 「Microsoft HTML Object Library」の参照設定
Private element As Object 'HTMLLIElement
 
Private Const CheckFolder As String = "drivercheck"
Private Const zipFile As String = "howa1.zip"

Private profile As String
Private Keys As New Selenium.Keys
Private lp As Long
Private Const defWaitMS As Long = 500
Private Const LpWaitCnt As Long = 30
Public Function SeleniumOpen(ByRef driver As Selenium.ChromeDriver) As Boolean
'====================================================================================================
'普通にChromeを立ち上げて後からChromeDriverで掴みに行く
'====================================================================================================
Select Case True
    Case Len(Environ("TMP")) > 0
        profile = Environ("TMP") & "\userdata"
    Case Len(Environ("TEMP"))
        profile = Environ("TEMP") & "\userdata"
    Case Else
        profile = ThisWorkbook.Path & "\userdata"
End Select
On Error Resume Next '---プロセスファイルを掴んでいる場合はスキップする
With CreateObject("Scripting.FileSystemObject")
    If .FolderExists(profile) = True Then '---一時プロファイル用にフォルダがあれば削除
        .DeleteFolder profile
    End If
    .CreateFolder profile '---一時プロファイル用にフォルダを作る
End With
CreateObject("WScript.Shell").Run ("chrome.exe --remote-debugging-port=9222 --user-data-dir=""" & profile & "")
On Error GoTo 0
driver.SetCapability "debuggerAddress", "127.0.0.1:9222"
End Function
Public Function SeleniumClose(ByRef driver As Selenium.ChromeDriver) As Boolean
'====================================================================================================
'Chromeを落としつつ一時プロファイルフォルダを削除する
'====================================================================================================
On Error Resume Next
driver.Close
driver.Quit
With CreateObject("Scripting.FileSystemObject")
    If .FolderExists(profile) = True Then
        .DeleteFolder profile
    End If
End With
On Error GoTo 0
Set driver = Nothing
End Function
Public Function ViewCheck(ByVal driver As Selenium.WebDriver, ByVal by As Selenium.by, Optional CheckMode As Long = 0, Optional ByVal Index As Long = 1) As Boolean
If driver.FindElements(by).Count > 0 Then
    ViewCheck = ViewCheckElm(driver, driver.FindElements(by)(Index), CheckMode)
Else
    ViewCheck = False
End If
End Function
Public Function ViewCheck(ByVal driver As Selenium.WebDriver, ByVal By As Selenium.By, Optional CheckMode As Long = 0, Optional ByVal Index As Long = 1, Optional TotalWaitSec As Long = 30) As Boolean
RemainingSec = TotalWaitSec
Do While RemainingSec > 0 '---要素が存在するかチェック
    If driver.FindElements(By).Count >= Index Then
        ViewCheck = ViewCheckElm(driver, driver.FindElements(By)(Index), CheckMode, RemainingSec)
        Exit Function
    End If
    driver.Wait 1000
    RemainingSec = RemainingSec - 1
Loop
ViewCheck = False
End Function
Public Function ViewCheckElm(ByVal driver As Selenium.WebDriver, element As Selenium.WebElement, Optional CheckMode As Long = 0, Optional TotalWaitSec As Long = 30) As Boolean
'==============================
'CheckMode
'0:活性化しているかまで
'1:画面上に表示されているかまで
'2:DOMに存在しているかまで
'==============================
On Error GoTo ErrEnd
RemainingSec = TotalWaitSec
With element
    Do While RemainingSec > 0 '---要素が存在するかチェック
        If .IsPresent = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsPresent = False Then '---ループを抜けても要素が見つからないと言うことは失敗扱い
        ViewCheckElm = False
        Exit Function
    End If
    
    If CheckMode <= 1 Then
        Do While RemainingSec > 0 '---要素が見えているかチェック
            If .IsDisplayed = True Then
                Exit Do
            Else
                DoEvents
                driver.Wait 1000 '---1秒待機
            End If
            RemainingSec = RemainingSec - 1
        Loop
        If .IsDisplayed = False Then '---ループを抜けても見つからないと言うことは失敗扱い
            ViewCheckElm = False
            Exit Function
        End If
    End If
    
    If CheckMode <= 2 Then
        If .IsEnabled = False Then '---活性化しているかチェック
            ViewCheckElm = False
            Exit Function
        End If
    End If
End With
ViewCheckElm = True
On Error GoTo 0
Exit Function
ErrEnd:
ViewCheckElm = False
Debug.Print Err.Description
End Function
Public Function InputText(ByVal driver As Selenium.WebDriver, ByVal By As Selenium.By, ByVal str As String, Optional AppendMode As Boolean = False, Optional ByVal Index As Long = 1, Optional WaitMS = defWaitMS, Optional TotalWaitSec As Long = 30, Optional ClearWaitMS As Long = 500) As Boolean
'====================================================================================================
'InputTextElmの亜種
'====================================================================================================
If driver.FindElements(By).Count > 0 Then
    InputText = InputTextElm(driver, driver.FindElements(By)(Index), str, AppendMode, WaitMS, TotalWaitSec)
Else
    InputText = False
End If
End Function
Public Function InputTextElm(ByVal driver As Selenium.WebDriver, element As Selenium.WebElement, ByVal str As String, Optional AppendMode As Boolean = False, Optional WaitMS = defWaitMS, Optional TotalWaitSec As Long = 30, Optional ClearWaitMS As Long = 500) As Boolean
'====================================================================================================
'文字入力を色々考慮しながらやる
'====================================================================================================
On Error GoTo ErrEnd
RemainingSec = TotalWaitSec
With element
    Do While RemainingSec > 0 '---要素が存在するかチェック
        driver.Timeouts.ImplicitWait = 30
        If .IsPresent = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsPresent = False Then '---ループを抜けても要素が見つからないと言うことは失敗扱い
        InputTextElm = False
        Exit Function
    End If
    
    Do While RemainingSec > 0 '---要素が見えているかチェック
        If .IsDisplayed = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsDisplayed = False Then '---ループを抜けても見つからないと言うことは失敗扱い
        InputTextElm = False
        Exit Function
    End If
    
    If .IsEnabled = False Then '---活性化しているかチェック
        InputTextElm = False
        Exit Function
    End If
    
    focusToElement driver, element
    .Click '---念のためクリックしてアクティブにする
    If AppendMode = False Then '---追記モード判定
        .Clear '---クリアしないと追記されてしまう
    End If
    driver.Wait ClearWaitMS '---稀にクリア直後に入力すると失敗することがあるので0.1秒だけ待機
    .SendKeys str
    .SendKeys Keys.Tab '---カーソルアウトで発火するJavaScript対策
    driver.Wait WaitMS '---規定秒数待機
End With
InputTextElm = True
On Error GoTo 0
Exit Function
ErrEnd:
InputTextElm = False
Debug.Print Err.Description
End Function
Public Function InputTextScript(ByVal driver As Selenium.WebDriver, cssselectors As String, ByVal str As String, Optional ByVal Index As Long = 0, Optional WaitMS = defWaitMS, Optional TotalWaitSec As Long = 30) As Boolean
'====================================================================================================
'文字入力を色々考慮しながらやる ※Clearが効かないサイトがあるのでJavaScriptで実行する時用
'====================================================================================================
On Error GoTo ErrEnd
Dim element As Selenium.WebElement
Set element = driver.FindElementsByCss(cssselectors)(Index + 1)
With element
    driver.Timeouts.ImplicitWait = 30
    RemainingSec = TotalWaitSec
    Do While RemainingSec > 0 '---要素が存在するかチェック
        If .IsPresent = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsPresent = False Then '---ループを抜けても要素が見つからないと言うことは失敗扱い
        InputTextScript = False
        Exit Function
    End If
    
    Do While RemainingSec > 0 '---要素が見えているかチェック
        If .IsDisplayed = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsDisplayed = False Then '---ループを抜けても見つからないと言うことは失敗扱い
        InputTextScript = False
        Exit Function
    End If
    
    If .IsEnabled = False Then '---活性化しているかチェック
        InputTextScript = False
        Exit Function
    End If
    
    driver.ExecuteScript ("document.querySelectorAll('" & cssselectors & "')[" & Index & "].value='" & str & "'") '---JavaScriptで文字入力
    .SendKeys Keys.Tab '---カーソルアウトで発火するJavaScript対策
    driver.Wait WaitMS '---規定秒数待機
End With
InputTextScript = True
Set element = Nothing
On Error GoTo 0
Exit Function
ErrEnd:
InputTextScript = False
Debug.Print Err.Description
Set element = Nothing
End Function
Public Function GetText(ByVal driver As Selenium.WebDriver, ByVal By As Selenium.By, Optional TargetAttr As String = "default", Optional ByVal Index As Long = 1, Optional TotalWaitSec As Long = 30) As String
'====================================================================================================
'GetTextElmの亜種
'====================================================================================================
If driver.FindElements(By).Count > 0 Then
    GetText = GetTextElm(driver, driver.FindElements(By)(Index), TargetAttr, TotalWaitSec)
Else
    GetText = False
End If
End Function
Public Function GetTextElm(ByVal driver As Selenium.WebDriver, element As Selenium.WebElement, Optional TargetAttr As String = "default", Optional TotalWaitSec As Long = 30) As String
'====================================================================================================
'データ取得をText以外からもできるようにしている
'====================================================================================================
On Error GoTo ErrEnd
With element
    RemainingSec = TotalWaitSec
    Do While RemainingSec > 0 '---要素が存在するかチェック※待機秒数はLpWaitCntで指定
        If .IsPresent = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsPresent = False Then '---ループを抜けても要素が見つからないと言うことは失敗扱い
        GetTextElm = vbNullString
        Exit Function
    End If
        
    Select Case LCase(TargetAttr) '---属性指定で取得できるようにする
        Case "default"
            GetTextElm = .Text '---textの取得が基本
            If Len(Trim(GetTextElm)) = 0 Then '---よく使いそうなValueはデフォルトでも補完対象にしておく
                GetTextElm = .value
            End If
        Case "text" '---明示的にtextを指定するならValueは考慮しない
            GetTextElm = .Text
        Case Else
            GetTextElm = .Attribute(TargetAttr)
    End Select
End With
On Error GoTo 0
GetTextElm = Trim(GetTextElm)
Exit Function
ErrEnd:
GetTextElm = vbNullString
Debug.Print Err.Description
End Function
Public Function ButtonClick(driver As Selenium.WebDriver, By As Selenium.By, Optional Index As Long = 1, Optional WaitMS = defWaitMS, Optional TotalWaitSec As Long = 30) As Boolean
'====================================================================================================
'ButtonClickElmの亜種
'====================================================================================================
If driver.FindElements(By).Count > 0 Then
    ButtonClick = ButtonClickElm(driver, driver.FindElements(By)(Index), WaitMS, TotalWaitSec)
Else
    ButtonClick = False
End If
End Function
Public Function ButtonClickElm(driver As Selenium.WebDriver, element As Selenium.WebElement, Optional WaitMS = defWaitMS, Optional TotalWaitSec As Long = 30) As Boolean
'====================================================================================================
'ボタンクリックを色々考慮しながらやる
'====================================================================================================
On Error GoTo ErrEnd
With element
    RemainingSec = TotalWaitSec
    Do While RemainingSec > 0 '---要素が存在するかチェック※待機秒数はLpWaitCntで指定
        If .IsPresent = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---1秒待機
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsPresent = False Then '---ループを抜けても要素が見つからないと言うことは失敗扱い
        ButtonClickElm = False
        Exit Function
    End If
    
    Do While RemainingSec > 0 '---要素が見えているかチェック※待機秒数はLpWaitCntで指定
        If .IsDisplayed = True Then
            Exit Do
        Else
            DoEvents
            driver.Wait 1000 '---あえて変数ではなくて1秒待機で固定している
        End If
        RemainingSec = RemainingSec - 1
    Loop
    If .IsDisplayed = False Then '---ループを抜けても見つからないと言うことは失敗扱い
        ButtonClickElm = False
        Exit Function
    End If
    
    If .IsEnabled = False Then '---活性化しているかチェック
        ButtonClickElm = False
        Exit Function
    End If
    .Click
    driver.Wait WaitMS '---規定秒数待機
End With
ButtonClickElm = True
On Error GoTo 0
Exit Function
ErrEnd:
ButtonClickElm = False
Debug.Print Err.Description
End Function
Public Function ChromeDriverVersionCheck() As Boolean
'====================================================================================================
'ChromeDriverを自動更新する
'====================================================================================================
Set objFso = CreateObject("Scripting.FileSystemObject")
'---SeleniumBasicのフォルダを探す
Select Case True
    Case objFso.FolderExists(Environ("ProgramFiles(x86)") & "\SeleniumBasic")
        ChromeDriverPath = Environ("ProgramFiles(x86)") & "\SeleniumBasic"
    Case objFso.FolderExists(Environ("ProgramFiles") & "\SeleniumBasic")
        ChromeDriverPath = Environ("ProgramFiles") & "\SeleniumBasic"
    Case objFso.FolderExists(Environ("ProgramW6432") & "\SeleniumBasic")
        ChromeDriverPath = Environ("ProgramW6432") & "\SeleniumBasic"
    Case objFso.FolderExists(Environ("LOCALAPPDATA") & "\SeleniumBasic")
        ChromeDriverPath = Environ("LOCALAPPDATA") & "\SeleniumBasic"
    Case Else
        MsgBox "'SeleniumBasic'のフォルダが見つかりません", vbCritical
        Exit Function
End Select
'---Chrome本体のフォルダを探す
Select Case True
    Case objFso.FolderExists(Environ("ProgramFiles(x86)") & "\Google\Chrome\Application")
        ChromePath = Environ("ProgramFiles(x86)") & "\Google\Chrome\Application"
    Case objFso.FolderExists(Environ("ProgramFiles") & "\Google\Chrome\Application")
        ChromePath = Environ("ProgramFiles") & "\Google\Chrome\Application"
    Case objFso.FolderExists(Environ("ProgramW6432") & "\Google\Chrome\Application")
        ChromePath = Environ("ProgramW6432") & "\Google\Chrome\Application"
    Case objFso.FolderExists(Environ("LOCALAPPDATA") & "\Google\Chrome\Application")
        ChromePath = Environ("LOCALAPPDATA") & "\Google\Chrome\Application"
    Case Else
        MsgBox "'Chrome'フォルダが見つかりません", vbCritical
        Exit Function
End Select
 
Set objFso = Nothing
With ChromeVersion
    .Major = 1
    .Minor = 0
    .Build = 0
    .Revision = 0
End With
Call GetChromeVersion(ChromeVersion.Major, ChromeVersion.Minor, ChromeVersion.Build, ChromeVersion.Revision, ChromeDriverVersion.strVersion) '---Chrome.exeのバージョンを取得する
Call GetChromeDriverVersion(ChromeDriverVersion.Major, ChromeDriverVersion.Minor, ChromeDriverVersion.Build, ChromeDriverVersion.Revision, ChromeDriverVersion.strVersion) '---ChromeDriverのバージョンを取得する
If ChromeVersion.Major > ChromeDriverVersion.Major Then '---メジャーが更新されていたら
    NewDriverVersion = UpdateChromeChromeDriver(Join(Array(ChromeVersion.Major, ChromeVersion.Minor, ChromeVersion.Build), "."), ChromeDriverVersion.Revision)
    RtnCD = WritePrivateProfileString(SecName, KeyName, NewDriverVersion, ChromeDriverPath & "\" & ConfigFile) '---iniを上書きする

ElseIf ChromeVersion.Minor > ChromeDriverVersion.Minor Then '---マイナ―が更新されていたら
    NewDriverVersion = UpdateChromeChromeDriver(Join(Array(ChromeVersion.Major, ChromeVersion.Minor, ChromeVersion.Build), "."), ChromeDriverVersion.Revision)
    RtnCD = WritePrivateProfileString(SecName, KeyName, NewDriverVersion, ChromeDriverPath & "\" & ConfigFile) '---iniを上書きする

ElseIf ChromeVersion.Build > ChromeDriverVersion.Build Then '---ビルドが更新されていたら
    NewDriverVersion = UpdateChromeChromeDriver(Join(Array(ChromeVersion.Major, ChromeVersion.Minor, ChromeVersion.Build), "."), ChromeDriverVersion.Revision)
    RtnCD = WritePrivateProfileString(SecName, KeyName, NewDriverVersion, ChromeDriverPath & "\" & ConfigFile) '---iniを上書きする

ElseIf ChromeVersion.Revision > ChromeDriverVersion.Revision Then '---リビジョンが更新されていたら
    NewDriverVersion = UpdateChromeChromeDriver(Join(Array(ChromeVersion.Major, ChromeVersion.Minor, ChromeVersion.Build), "."), ChromeVersion.Revision)
    RtnCD = WritePrivateProfileString(SecName, KeyName, NewDriverVersion, ChromeDriverPath & "\" & ConfigFile) '---iniを上書きする
End If

'---テスト運転
On Error GoTo ErrTest
With CreateObject("Selenium.ChromeDriver")
    .AddArgument ("--headless")
    .Start
    .Get ("https://javeo.jp")
    .Close
    .Quit
End With
ChromeDriverVersionCheck = True
Exit Function
ErrTest:
    MsgBox "ChromeDriverの起動に失敗しました", vbCritical
    ChromeDriverVersionCheck = False
End Function
Private Function GetChromeVersion(ByRef Major As Long, ByRef Minor As Long, ByRef Build As Long, ByRef Revision As Long, ByRef strVersion As String)
'====================================================================================================
'Chrome.exeと同じフォルダにバージョン名のフォルダがあるのでそこからバージョンを取得する
'====================================================================================================
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objRE = CreateObject("VBScript.RegExp")
 
With objRE '---正規表現の準備
    .Pattern = "([0-9]+(?=\.))"
    .Global = True
End With
For Each objFolder In objFso.GetFolder(ChromePath).SubFolders
    If objRE.test(objFolder.Name) Then '---正規表現でフォルダ名をマッチさせてバージョンを取得する
        strVersion = objFolder.Name
        If Major < CLng(Split(strVersion, ".")(0)) Then
            Major = CLng(Split(strVersion, ".")(0))
            Minor = CLng(Split(strVersion, ".")(1))
            Build = CLng(Split(strVersion, ".")(2))
            Revision = CLng(Split(strVersion, ".")(3))
        ElseIf Minor < CLng(Split(strVersion, ".")(1)) Then
            Minor = CLng(Split(strVersion, ".")(1))
            Build = CLng(Split(strVersion, ".")(2))
            Revision = CLng(Split(strVersion, ".")(3))
        ElseIf Build < CLng(Split(strVersion, ".")(2)) Then
            Build = CLng(Split(strVersion, ".")(2))
            Revision = CLng(Split(strVersion, ".")(3))
        ElseIf Revision < CLng(Split(strVersion, ".")(3)) Then
            Revision = CLng(Split(strVersion, ".")(3))
        End If
    End If
Next objFolder
 
Set objRE = Nothing
Set objFso = Nothing
End Function
Private Function GetChromeDriverVersion(ByRef Major As Long, ByRef Minor As Long, ByRef Build As Long, ByRef Revision As Long, ByRef strVersion As String)
'====================================================================================================
'ChromeDriverと同じフォルダにconfig.iniを保存してバージョンを管理して取得する
'====================================================================================================
Set objFso = CreateObject("Scripting.FileSystemObject")
 
If objFso.FileExists(ChromeDriverPath & "\" & ConfigFile) Then
    strVersion = ReadIni(ChromeDriverPath & "\" & ConfigFile, SecName, KeyName, Default)
    Major = CLng(Split(strVersion, ".")(0))
    Minor = CLng(Split(strVersion, ".")(1))
    Build = CLng(Split(strVersion, ".")(2))
    Revision = CLng(Split(strVersion, ".")(3))
Else '---config.iniが無いなら作る
    GetChromeDriverVersion = Default '---初期値
    intFF = FreeFile
    Open ChromeDriverPath & "\" & ConfigFile For Output As #intFF
        Major = 1
        Minor = 0
        Build = 0
        Revision = 0
        strVersion = Default
        Print #intFF, "[ChromeDriver]"
        Print #intFF, "ChromeVersion = " & Default
    Close
End If
 
If objFso.FolderExists(ChromeDriverPath & "\" & CheckFolder) = False Then '---zip保存用フォルダが無かったら作成しておく
    objFso.CreateFolder ChromeDriverPath & "\" & CheckFolder
End If
Set objFso = Nothing
End Function
Private Function UpdateChromeChromeDriver(ByVal TargetChromeDriverVersion As String, ByRef Revision As Long) As String
'====================================================================================================
'https://chromedriver.chromium.org/downloadsのソースを分解してChromeのバージョンに合わせたChromeDriverをダウンロードして保存する
'====================================================================================================
Set xmlhttp = CreateObject("MSXML2.XMLHTTP")
Set htmlDoc = CreateObject("HTMLFile")
'Set htmlDoc = New HTMLDocument
Dim strReleaseVersion As String
With xmlhttp
    .Open "GET", "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" & TargetChromeDriverVersion '---Chromeドライバーが公開されているサイトからソースを取得
    .Send
    Do While .readyState < 4
        DoEvents
    Loop
    strReleaseVersion = .responseText
    If CLng(Split(strReleaseVersion, ".")(3)) > Revision Then '---リビジョンだけだと更新版がない可能性がある
        strUrl = "https://chromedriver.storage.googleapis.com/" & strReleaseVersion & "/chromedriver_win32.zip"
        URLDownloadToFile 0, strUrl, ChromeDriverPath & "\" & CheckFolder & "\" & zipFile, 0, 0 '---ファイルをダウンロードするWinAPI
        On Error Resume Next
        Application.DisplayAlerts = False
        Kill ChromeDriverPath & "\" & "chromedriver.exe" '---今のドライバーを削除する
        With CreateObject("Shell.Application") '---zipを既定のフォルダに向けて解凍する
            .Namespace((ChromeDriverPath)).CopyHere .Namespace((ChromeDriverPath & "\" & CheckFolder & "\" & zipFile)).Items
        End With
        Application.DisplayAlerts = True
        On Error GoTo 0
    End If
End With

UpdateChromeChromeDriver = strReleaseVersion
Set htmlDoc = Nothing
Set xmlhttp = Nothing
End Function
Private Function ReadIni(ByVal FName As String, ByVal SName As String, ByVal KName As String, ByVal Default As String) As String
'====================================================================================================
'WinAPIでiniファイルから情報を取得する
'====================================================================================================
RtnStr = Space$(256)
RtnCD = GetPrivateProfileString(SName, KName, Default, RtnStr, 255, FName)
     
' 戻り値設定
If RtnCD > 0 Then
    If InStr(RtnStr, Chr$(0)) > 0 Then
        ReadIni = Left$(RtnStr, InStr(RtnStr, Chr$(0)) - 1)
    Else
        ReadIni = ""
    End If
Else
    ReadIni = Default
End If
End Function
Public Function focusToElement(ByVal driver As Selenium.WebDriver, ByVal element As Selenium.WebElement)
'====================================================================================================
'指定した要素にスクロールさせる
'====================================================================================================
Dim Actions As Selenium.Actions
Set Actions = driver.Actions.MoveToElement(element)
Actions.Perform
Set Actions = Nothing
End Function
Public Function RegExpFunc(Target As String, strPattern As String, Optional Idx As Long = 0, Optional strDelimiter As String = "") As String
'====================================================================================================
'正規表現の結果を返す
'====================================================================================================
'Dim objReg As New VBScript_RegExp_55.RegExp             '---参照設定してればこれでもok
'Dim objMatchColl As VBScript_RegExp_55.MatchCollection  '---参照設定してればこれでもok
'Dim objMatch As VBScript_RegExp_55.Match                '---参照設定してればこれでもok
Dim objReg As Object
Dim objMatchColl As Object
Dim objMatch As Object


Set objReg = CreateObject("VBScript.RegExp")
With objReg
    .Pattern = strPattern   '---正規表現のパターン
    .IgnoreCase = False     '---大文字小文字の区別をする
    .Global = True          '---複数回マッチした場合は全て取得する
    Set objMatchColl = .Execute(Target)
End With

'---Idxで指定したIndexのデータを取得する
RegExpFunc = vbNullString
If objMatchColl.Count > Idx Then
    If Idx = -1 Then '---idxを-1でしていた時はobjMatchCollの結合モードにする
        For Each objMatch In objMatchColl
            RegExpFunc = RegExpFunc & strDelimiter & objMatch
        Next
        RegExpFunc = Replace(RegExpFunc, strDelimiter, "", 1, 1) '---先頭に余計なデリミタがあるから一度だけReplaceで削除する
    Else
        RegExpFunc = objMatchColl(Idx)
    End If
End If

Set objMatch = Nothing
Set objReg = Nothing
End Function

タイトルとURLをコピーしました