はじめに
これは、Visual Basic Advent Calendar 2023の22日目の記事となります。
これまで、ExcelでWebスクレイピングをするのに、TinySeleniumVBA および SeleniumVBA(TinySeleniumVBA 機能強化版) を紹介してきました。
TinySeleniumVBA では、WebブラウザのバージョンアップがあるとSelenium WebDriverの更新が必要になります。これについては、yamato1413 さんが WebDriver 自動更新の別途モジュール(WebDriverManager-for-VBA)を提供しています。
Playwright や Puppeteer のように DevTools プロトコル対応すれば、Selenium WebDriver 自体が不要となります。誰かVBAでやってないかと検索してみると、昨年既に公開されてました。
コメント欄で作者の方と相談して、製品名は製品の特徴である「何もインストールしない」を謳った「ZeroInstall BrowserDriver for VBA」、略して「ZeroInstallBDr」となりました。
導入準備
1.上記のGitHubのページから、<> Code
ボタンをクリックして、「DownLoad Zip」を選択します。
2.ダウンロードされた「ChromeControler-No-Selenium-WebDriver-VBAJSON-master.zip」ファイルをを展開します。
3.ExcelのVBE(Visual Basic Editor)を開きます。
4.展開したファイルをプロジェクト画面にドラッグ&ドロップするだでインポートされます。
5.標準モジュールを追加して、コードを記述します。
使用方法
現在実装されているメソッドなどは、Wikiに記載されています。Sleepについては、Driver.SleepByWinAPI で実装されています。
ZeroInstallBDrでWebアプリ操作
下記記事で使用したサンプルの体脂肪率を計算するサイトで身長と体重をセットして体脂肪率を求めてみます。
Excelらしくセルに身長と体重をセットして、体脂肪率のセルに値をセットされるようにします。
ソースコード
Option Explicit
Public Sub Main()
' Start WebDriver (Edge)
Dim Driver As IWebDriver
Set Driver = New EdgeDriver
' BMI計算サイト
Driver.OpenURL ("https://keisan.casio.jp/exec/system/1161228728")
' 身長をセット
Dim height
Set height = Driver.FindElementById("var_身長")
height.SetValue Cells(1, 2).value
' 体重をセット
Dim weight
Set weight = Driver.FindElementById("var_体重")
weight.SetValue Cells(2, 2).value
' ボタンクリック
Driver.FindElementById("executebtn").Click
' 1秒待機
Driver.SleepByWinAPI 1000
' BMIをセット
Dim bmi
Set bmi = Driver.FindElementById("ans1")
Cells(3, 2).value = bmi.GetTextContent
' Close
Driver.CloseWindow
End Sub
補足
現状は、"var_身長"といった日本語は認識してくれません。"var_\u8eab\u9577"とUnicode 変換したものを使用することで対応できます。
【2023/12/22追記】
早々に修正版を公開して頂き、日本語で認識されるようになりました。ソースコードも修正しておきました。
Unicode 変換ツール
実行
体脂肪率ボタンをクリックすると、Keisan 生活や実務に役立つ計算サイト - 体脂肪率のサイトが開きます。身長と体重をセットして自動で計算ボタンをクリックします。
注意点
Edgeで起動したのにタイトルがChromeのままなのは、作者に報告しておきます。
【2023/12/22追記】
早々に修正版を公開して頂き、修正されました。
イミディエイトウィンドウ
実行するとデバッグ情報としてイミディエイトウィンドウに下記の情報が出力されます。
>>>>>>送信内容:{"id": 1,"method": "Target.setDiscoverTargets","params": {"discover": true}}
受信:{"method":"Target.targetCreated","params":{"targetInfo":{"targetId":"30DA9B2A1E155161DD729C771CF5954A","type":"page","title":"\u65b0\u3057\u3044\u30bf\u30d6","url":"edge://newtab/","attached":true,"canAccessOpener":false,"browserContextId":"A633A1A63709DDC83C1E4BFFE155CD8C","pid":3792}}}
受信:{"id":1,"result":{}}
>>>>>>送信内容:{"id": 2,"method": "Target.attachToTarget","params": {"targetId": "30DA9B2A1E155161DD729C771CF5954A"}}
受信:{"method":"Target.attachedToTarget","params":{"sessionId":"E70A8D892FCF42EA409A8EEDEE4AE96B","targetInfo":{"targetId":"30DA9B2A1E155161DD729C771CF5954A","type":"page","title":"\u65b0\u3057\u3044\u30bf\u30d6","url":"edge://newtab/","attached":true,"canAccessOpener":false,"browserContextId":"A633A1A63709DDC83C1E4BFFE155CD8C","pid":3792},"waitingForDebugger":false}}
受信:{"id":2,"result":{"sessionId":"E70A8D892FCF42EA409A8EEDEE4AE96B"}}
>>>>>>送信内容:{"id": 3,"method": "Page.navigate","params": {"url": "https://keisan.casio.jp/exec/system/1161228728"}}
受信:{"id":3,"result":{"frameId":"30DA9B2A1E155161DD729C771CF5954A","loaderId":"D14DF250D7D15A2967137381DBD4A8F8"}}
>>>>>>送信内容:{"id": 4,"method": "Runtime.evaluate","params": {"expression": "document.readyState;","returnByValue": false}}
受信:{"method":"Target.targetInfoChanged","params":{"targetInfo":{"targetId":"30DA9B2A1E155161DD729C771CF5954A","type":"page","title":"keisan.casio.jp/exec/system/1161228728","url":"https://keisan.casio.jp/exec/system/1161228728","attached":true,"canAccessOpener":false,"browserContextId":"A633A1A63709DDC83C1E4BFFE155CD8C","pid":4440}}}
受信:{"id":4,"result":{"result":{"type":"string","value":"complete"}}}
>>>>>>送信内容:{"id": 5,"method": "Target.setDiscoverTargets","params": {"discover": true}}
受信:{"id":5,"result":{}}
>>>>>>送信内容:{"id": 6,"method": "Page.enable"}
受信:{"id":6,"result":{}}
>>>>>>送信内容:{"id": 7,"method": "Runtime.evaluate","params": {"expression": "document;","returnByValue": false}}
受信:{"id":7,"result":{"result":{"type":"object","subtype":"node","className":"HTMLDocument","description":"#document","objectId":"2503311007000268046.1.1"}}}
>>>>>>送信内容:{"id": 8,"method": "DOM.getDocument","params": {"depth": 1}}
受信:{"id":8,"result":{"root":{"nodeId":1,"backendNodeId":1,"nodeType":9,"nodeName":"#document","localName":"","nodeValue":"","childNodeCount":2,"children":[{"nodeId":2,"parentId":1,"backendNodeId":31,"nodeType":10,"nodeName":"html","localName":"","nodeValue":"","publicId":"","systemId":""},{"nodeId":3,"parentId":1,"backendNodeId":32,"nodeType":1,"nodeName":"HTML","localName":"html","nodeValue":"","childNodeCount":2,"attributes":["lang","ja"],"frameId":"30DA9B2A1E155161DD729C771CF5954A"}],"documentURL":"https://keisan.casio.jp/exec/system/1161228728","baseURL":"https://keisan.casio.jp/exec/system/1161228728","xmlVersion":"","compatibilityMode":"NoQuirksMode"}}}
>>>>>>送信内容:{"id": 9,"method": "Runtime.evaluate","params": {"expression": "document.getElementById('var_\u8eab\u9577');","returnByValue": false}}
受信:{"id":9,"result":{"result":{"type":"object","subtype":"node","className":"HTMLInputElement","description":"input#var_\u8eab\u9577.text","objectId":"2503311007000268046.1.2"}}}
>>>>>>送信内容:{"id": 10,"method": "DOM.describeNode","params": {"objectId": "2503311007000268046.1.2","depth": 1,"pierce": false}}
受信:{"id":10,"result":{"node":{"nodeId":0,"backendNodeId":33,"nodeType":1,"nodeName":"INPUT","localName":"input","nodeValue":"","childNodeCount":0,"children":[],"attributes":["size","10","autocomplete","off","type","text","name","var_\u8eab\u9577","id","var_\u8eab\u9577","value","","class","text"],"shadowRoots":[{"nodeId":0,"backendNodeId":34,"nodeType":11,"nodeName":"#document-fragment","localName":"","nodeValue":"","childNodeCount":1,"shadowRootType":"user-agent"}]}}}
>>>>>>送信内容:{"id": 11,"method": "DOM.focus","params": {"objectId": "2503311007000268046.1.2"}}
受信:{"id":11,"result":{}}
>>>>>>送信内容:{"id": 12,"method": "Input.dispatchKeyEvent","params": {"type": "keyDown","modifiers": 0,"windowsVirtualKeyCode": 13}}
受信:{"id":12,"result":{}}
>>>>>>送信内容:{"id": 13,"method": "Input.dispatchKeyEvent","params": {"type": "keyUp","modifiers": 0,"windowsVirtualKeyCode": 13}}
受信:{"id":13,"result":{}}
>>>>>>送信内容:{"id": 14,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(value){value = decodeURI(value);this.value = value;}","arguments": [{"value": "180"}],"objectId": "2503311007000268046.1.2"}}
受信:{"id":14,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 15,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){this.dispatchEvent(new CustomEvent('input', {bubbles: true}));}","arguments": [{"value": "180"}],"objectId": "2503311007000268046.1.2"}}
受信:{"id":15,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 16,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){this.dispatchEvent(new CustomEvent('change', {bubbles: true}));}","arguments": [{"value": "180"}],"objectId": "2503311007000268046.1.2"}}
受信:{"id":16,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 17,"method": "Runtime.evaluate","params": {"expression": "document.getElementById('var_\u4f53\u91cd');","returnByValue": false}}
受信:{"id":17,"result":{"result":{"type":"object","subtype":"node","className":"HTMLInputElement","description":"input#var_\u4f53\u91cd.text","objectId":"2503311007000268046.1.3"}}}
>>>>>>送信内容:{"id": 18,"method": "DOM.describeNode","params": {"objectId": "2503311007000268046.1.3","depth": 1,"pierce": false}}
受信:{"id":18,"result":{"node":{"nodeId":0,"backendNodeId":35,"nodeType":1,"nodeName":"INPUT","localName":"input","nodeValue":"","childNodeCount":0,"children":[],"attributes":["size","10","autocomplete","off","type","text","name","var_\u4f53\u91cd","id","var_\u4f53\u91cd","value","","class","text"],"shadowRoots":[{"nodeId":0,"backendNodeId":36,"nodeType":11,"nodeName":"#document-fragment","localName":"","nodeValue":"","childNodeCount":1,"shadowRootType":"user-agent"}]}}}
>>>>>>送信内容:{"id": 19,"method": "DOM.focus","params": {"objectId": "2503311007000268046.1.3"}}
受信:{"id":19,"result":{}}
>>>>>>送信内容:{"id": 20,"method": "Input.dispatchKeyEvent","params": {"type": "keyDown","modifiers": 0,"windowsVirtualKeyCode": 13}}
受信:{"id":20,"result":{}}
>>>>>>送信内容:{"id": 21,"method": "Input.dispatchKeyEvent","params": {"type": "keyUp","modifiers": 0,"windowsVirtualKeyCode": 13}}
受信:{"id":21,"result":{}}
>>>>>>送信内容:{"id": 22,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(value){value = decodeURI(value);this.value = value;}","arguments": [{"value": "54"}],"objectId": "2503311007000268046.1.3"}}
受信:{"id":22,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 23,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){this.dispatchEvent(new CustomEvent('input', {bubbles: true}));}","arguments": [{"value": "54"}],"objectId": "2503311007000268046.1.3"}}
受信:{"id":23,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 24,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){this.dispatchEvent(new CustomEvent('change', {bubbles: true}));}","arguments": [{"value": "54"}],"objectId": "2503311007000268046.1.3"}}
受信:{"id":24,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 25,"method": "Runtime.evaluate","params": {"expression": "document.getElementById('executebtn');","returnByValue": false}}
受信:{"id":25,"result":{"result":{"type":"object","subtype":"node","className":"HTMLInputElement","description":"input#executebtn.bigbutton","objectId":"2503311007000268046.1.4"}}}
>>>>>>送信内容:{"id": 26,"method": "DOM.describeNode","params": {"objectId": "2503311007000268046.1.4","depth": 1,"pierce": false}}
受信:{"id":26,"result":{"node":{"nodeId":0,"backendNodeId":37,"nodeType":1,"nodeName":"INPUT","localName":"input","nodeValue":"","childNodeCount":0,"children":[],"attributes":["type","button","value"," \u8a08 \u7b97 ","onclick","return checkText()","class","bigbutton","id","executebtn"],"shadowRoots":[{"nodeId":0,"backendNodeId":38,"nodeType":11,"nodeName":"#document-fragment","localName":"","nodeValue":"","childNodeCount":1,"shadowRootType":"user-agent"}]}}}
>>>>>>送信内容:{"id": 27,"method": "DOM.focus","params": {"objectId": "2503311007000268046.1.4"}}
受信:{"id":27,"result":{}}
>>>>>>送信内容:{"id": 28,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){this.click();}","arguments": [{"value": ""}],"objectId": "2503311007000268046.1.4"}}
受信:{"id":28,"result":{"result":{"type":"undefined"}}}
>>>>>>送信内容:{"id": 29,"method": "Page.enable"}
受信:{"method":"Page.frameScheduledNavigation","params":{"frameId":"30DA9B2A1E155161DD729C771CF5954A","delay":0,"reason":"formSubmissionPost","url":"https://keisan.casio.jp/exec/system/1161228728"}}
受信:{"method":"Page.frameRequestedNavigation","params":{"frameId":"30DA9B2A1E155161DD729C771CF5954A","reason":"formSubmissionPost","url":"https://keisan.casio.jp/exec/system/1161228728","disposition":"currentTab"}}
受信:{"method":"Page.frameStartedLoading","params":{"frameId":"30DA9B2A1E155161DD729C771CF5954A"}}
受信:{"method":"Page.frameClearedScheduledNavigation","params":{"frameId":"30DA9B2A1E155161DD729C771CF5954A"}}
受信:{"method":"Target.targetInfoChanged","params":{"targetInfo":{"targetId":"30DA9B2A1E155161DD729C771CF5954A","type":"page","title":"keisan.casio.jp/exec/system/1161228728","url":"https://keisan.casio.jp/exec/system/1161228728","attached":true,"canAccessOpener":false,"browserContextId":"A633A1A63709DDC83C1E4BFFE155CD8C","pid":4440}}}
受信:{"method":"Page.frameNavigated","params":{"frame":{"id":"30DA9B2A1E155161DD729C771CF5954A","loaderId":"C2442CDBFD2FE4FF70259A5C499CEC94","url":"https://keisan.casio.jp/exec/system/1161228728","domainAndRegistry":"casio.jp","securityOrigin":"https://keisan.casio.jp","mimeType":"text/html","adFrameStatus":{"adFrameType":"none"},"secureContextType":"Secure","crossOriginIsolatedContextType":"NotIsolated","gatedAPIFeatures":[]},"type":"Navigation"}}
受信:{"method":"DOM.documentUpdated","params":{}}
受信:{"id":29,"result":{}}
>>>>>>送信内容:{"id": 30,"method": "DOM.enable"}
受信:{"method":"DOM.documentUpdated","params":{}}
受信:{"method":"Page.domContentEventFired","params":{"timestamp":109214.263145}}
受信:{"id":30,"result":{}}
>>>>>>送信内容:{"id": 31,"method": "Runtime.evaluate","params": {"expression": "document.getElementById('ans1');","returnByValue": false}}
受信:{"method":"Page.loadEventFired","params":{"timestamp":109214.390639}}
受信:{"method":"Page.frameStoppedLoading","params":{"frameId":"30DA9B2A1E155161DD729C771CF5954A"}}
受信:{"id":31,"result":{"result":{"type":"object","subtype":"node","className":"HTMLDivElement","description":"div#ans1.answaku","objectId":"2503311007000268046.2.1"}}}
>>>>>>送信内容:{"id": 32,"method": "DOM.describeNode","params": {"objectId": "2503311007000268046.2.1","depth": 1,"pierce": false}}
受信:{"id":32,"result":{"node":{"nodeId":0,"backendNodeId":77,"nodeType":1,"nodeName":"DIV","localName":"div","nodeValue":"","childNodeCount":1,"children":[{"nodeId":0,"parentId":0,"backendNodeId":78,"nodeType":3,"nodeName":"#text","localName":"","nodeValue":"33.4271"}],"attributes":["class","answaku","id","ans1"]}}}
>>>>>>送信内容:{"id": 33,"method": "Runtime.callFunctionOn","params": {"functionDeclaration": "function(){return this.textContent.replace(/\\s/g, ' ');}","arguments": [{"value": ""}],"objectId": "2503311007000268046.2.1"}}
受信:{"id":33,"result":{"result":{"type":"string","value":"33.4271"}}}
>>>>>>送信内容:{"id": 34,"method": "Browser.close"}
受信:{"id":34,"result":{}}
最後に
IE11サポート終了問題は、昨年の6月に終わりました。
会社によってはセキュリティーに厳しく「Selenium」と「WebDriver」の使用を禁止しているところもあるようです。そういう会社でもExcelだけは、プログラムが出来る唯一の希望だったりします。
ZeroInstallBDr作者のkabkabkabさんも、会社で「Selenium」と「WebDriver」の使用申請をしたところ却下され、しばらく放置していたがIEのサポート終了が迫ってきたこともあって、「CDPについて調べて自分で作ってみよう!」と思われて開発を始めたようです。
その後、会社でSelenium、WebDriverインストールOKな状況に変わったとのこと。
ExcelでWebスクレイピングする用途で、そこまで複雑なことは求められていないと思います。今回のサンプルのようにExcelと連携することで便利に使える利点もあります。
その他
開いているブラウザを操作することは、「ZeroInstallBDr」では対応していません。
下記サイトでは、パイプを使用して実現させているようです。