1 はじめに
諸事情により、やむを得ずリモートデバッグモード(port 9222)で作成したショートカットのアイコンで起動して手動でログインしたブラウザを起点として、自動化処理を行っている事例もあるかと思いますが、制約があります。
Discordコミュニティ「Excel-Fun.xls*」の議論で、リモートデバッグモードではcaps.SetDownloadPrefsによりダウンロード先を指定しようとしても、設定できずにエラーになることが判明しました。
また、driver.SetDownloadFolder(内部でCDPのPage.setDownloadBehavior を実行)しているが非推奨とされている)を利用すれば指定フォルダにはダウンロードできますが、その後手作業でダウンロードしようとすると動作不具合が起こることも判明しました。
2 対応
様々な手法を検討しましたが、ダウンロードURLを取得できてWebDriver上での操作にこだわりがなければ WindowsAPIの「UrlDownloadToFile」の利用により、問題なく処理できるものと思われます。
「UrlDownloadToFile」は、SeleniumVBAにおいてWebDriverの自動ダウンロードで利用していますので、すでに宣言済です。
テスト用のサイトとして、RPA Challengeを利用させていただき、Excelファイルをダウンロードできるようにしました。
3 処理手順
(1) 作成したショートカット(※)により、リモートデバッグモード(port 9222)でEdgeを手動で起動する。
(2) (以下自動処理)起動したEdgeを起点として、 自動処理を新規タブ(作業用タブ)を開いて開始する。その際、リモードデバッグモードでEdgeが立ち上がっていない場合はエラーになる関数(@いおり様提供)で判断して終了する。
(3) WindowsAPIの「UrlDownloadToFile」を利用して、Excelファイルを指定フォルダにダウンロード後、確認作業のため一旦停止する
(4) 作業用タブ(RPA Challenge)を閉じて処理を終了して初期状態のタブのみ残す
4 ExcelVBAコード紹介
以下のコードを丸ごとコピーして、新規の標準モジュールに貼り付けますと動作確認ができます。もし、SeleniumVBAがまったく初めての方は、こちらの記事を参考に新規の標準モジュール作成まで行ってください。
ダウンロードURLの特定は、XPathによりaタグをテキストから特定して、
そのhref属性の値をGetAttributeすることで取得しています。
ダウンロードフォルダの指定の際、ファイル名を指定する必要がありますが、
ファイル名は任意に設定できます。
Option Explicit
Sub Edge_RemoteDebugger()
'=================================================
'リモートデバッグによりログイン状態のブラウザを自動操作する。
'ショートカットにより、すでに立ち上げた状態から始める。
'=================================================
'ショートカットのリンク先は以下に設定(ログイン継続希望の場合は --guestは削除)
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --remote-debugging-port=9222 --user-data-dir="C:\EdgeDebugProfile --guest --disable-sync"
'=================================================
'URLの設定(RPA Challenge)
Const strURL As String = "https://www.rpachallenge.com"
'=================================================
Dim driver As SeleniumVBA.WebDriver
Dim caps As SeleniumVBA.WebCapabilities
'作業用タブ
Dim winTmp As SeleniumVBA.WebWindow
Dim wshell As Object
'9222ポートが開いていない場合は終了
If GetIs9222PortListening = False Then MsgBox "ショートカットを開いてください": Exit Sub
Set driver = SeleniumVBA.New_WebDriver
Set wshell = CreateObject("WScript.Shell")
driver.StartEdge
Set caps = driver.CreateCapabilities(initializeFromSettingsFile:=False)
caps.SetDebuggerAddress "localhost:9222"
driver.OpenBrowser caps
'作業用タブ(タブを新規で開く)
Set winTmp = driver.Windows.SwitchToNew(windowType:=svbaTab)
driver.NavigateTo strURL & "/?lang=ja"
'ダウンロードURLを特定する
Dim URL As String
URL = driver.FindElement(By.XPath, "//a[text()=' Excelファイルをダウンロード ']").GetAttribute("href")
URL = strURL & URL
'ファイル名を取得する(実際のところ拡張子が整合していればファイル名は任意)
Dim arrURL As Variant
Dim FileName As String
arrURL = Split(URL, "/")
FileName = arrURL(UBound(arrURL))
'downloadパスを現在のフォルダに指定する。ファイル名まで指定する必要あり
Dim downloadPath As String: downloadPath = ThisWorkbook.Path & "\" & FileName
'保存フォルダにdownloadする(UrlDownloadToFileはSeleniumVBAでは宣言済)
UrlDownloadToFile 0&, StrPtr(URL), StrPtr(downloadPath), 0&, 0
'ファイルが指定フォルダに存在するまで待機
Do While Dir(ThisWorkbook.Path & "\" & FileName, vbDirectory) = ""
driver.Wait 300 '300ミリ秒待機
Loop
Stop ’確認のため一時停止
'作業用タブを閉じる
winTmp.CloseIt
'元のタブを残したまま終了
driver.Shutdown
End Sub
Public Function GetIs9222PortListening() As Boolean
Dim t As Double
t = Timer
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
'コマンドプロンプトで実行した結果を取得する
'netstatコマンドについて
'a:全てのリッスンのポートを表示する
'n:数値に変換する(n入れないと遅いので注意)
'p:指定したプロトコルのみ表示する。TCPを指定するとIPv4のTCPのみ表示
Dim Exec As Object '今回9222がリッスンかどうかのみみるので、プロセスIDを取得する「o」は入れてない
Set Exec = wsh.Exec("cmd /c netstat -an -p TCP|find ""9222""|find ""LISTENING""")
Dim stdout As Object
Set stdout = Exec.stdout
Do While Exec.Status = 0
DoEvents
' Sleep 100
Loop
' Dim str As String
' str = Exec.stdout.ReadAll 'Exec.Status=1になった後なら、ReadAllでも素早く取得できる
Dim IsRtn As Boolean
IsRtn = False
Dim StrLine As String
Do Until stdout.AtEndOfStream
'1行ずつ読み出し
StrLine = stdout.ReadLine()
If StrLine Like "*TCP*:9222*:*LISTENING*" Then
'目的の行が見つかった時点でループから抜ける
IsRtn = True
Exit Do
End If
Loop
GetIs9222PortListening = IsRtn
Debug.Print Round(Timer - t, 2) & "秒"
End Function