VBAでSeleniumを使わずにEdgeブラウザ操作する

Excel
この記事は約39分で読めます。

VBAでEdgeブラウザを操作したいけど、環境整えるのにハードル高くて、ライブラリもインストールできない!VBAだけで何とかならないか!?と思って調査しました。

 

Webスクレイピングの基本についての記事もありますので、まずはそちらをチェックしておくことをおすすめします。

Webスクレイピングの基本!HTTP通信について

Webスクレイピングの基本!HTTP通信について
VBAでWebブラウザ操作を自動化するにあたって、基本的なことをまとめました。 VBAでのWebスクレイピングは初めてだったので、改めて基本的なことを学習したので、Webスクレイピングが初めての方にシンプルにお伝えできればと思います。 We...

Webスクレイピングの基本!要素の属性とXPathの調べ方

Webスクレイピングの基本!要素の属性とXPathの調べ方
VBAでWebブラウザ操作を自動化するにあたって、基本的なことをまとめました。 今回は、Webページ内の要素を操作するときに必要な、要素の情報を調べる方法です。Webスクレイピングが初めての方にシンプルにお伝えできればと思います。 Webペ...

 

 

IEサポート終了にともない他ブラウザ操作への移行を検討

VBAではCreateObject関数を使用してブラウザ操作ができますが、ブラウザがIEのみの対応です。

IEはすでにサポート切れのため、ブラウザ操作を実装しても、このままIEを使い続けるわけにはいかない。なんとか他のブラウザで、ブラウザ操作ができないかと調査を始めました。

 

VBAからのブラウザ操作には何か必要か?

他の方法でブラウザ操作をするために、何が必要かを調べました。

VBAでのブラウザ操作には、[WebDriver]と[ライブラリ]が必要ということがわかりました。

 

ブラウザ操作に必須のツールWebDriverについて

WebDriverとは、ユーザーの操作をシミュレートすることで、ブラウザの操作テストを行うことができるツールのことです。

このWebDriverを使って、VBAやRPAツール等からWebDriverに指示を出すことでブラウザ操作ができます。WebDriverは、ブラウザの種類(EdgeChromeなど)ごとにドライバーがあり、各PCにインストールして使用します。

EdgeWebDriver

Microsoft Edge WebDriver (英語) |Microsoft Edge 開発者

ChromeWebDriver

ダウンロード  |  ChromeDriver  |  Chrome for Developers

 

 

VBAからWebDriverに指示を出すためのライブラリの検討

VBAから、WebDriverにブラウザ操作の指示を出すために、基本的にはライブラリを使用します。ライブラリは、VBAや各プログラム言語からWebDriverに指示を出しやすくするために、WebDriverとの間の仲介役のような役割をします。

私が試したライブラリは以下の2つです。

 

SeleniumBasic

SeleniumBasic は、Web操作プログラムをVBAから作成できるライブラリです。このライブラリを使えば、ブラウザ操作でやりたいことがほぼできると思います。使える環境であれば優先的に使いたいライブラリです。

Release SeleniumBasic v2.0.9.0 · florentbr/SeleniumBasic
CHANGELOG.txt

 

VBAとSeleniumBasicを使用したWebブラウザ操作の方法についてはこちらにあります↓

VBAとSeleniumBasicライブラリでブラウザ操作自動化!

VBAとSeleniumBasicライブラリでブラウザ操作自動化!
毎日同じWebシステムで同じ操作をしていると、「ブラウザ操作を代わりに誰かやってくれないかな~」と思うことはありませんか?   SeleniumBasicを使えば、VBAからブラウザの操作を簡単に行うことができます。   Webスクレイピン...

 

SeleniumBasicは、各PCにインストールする必要があります。会社によっては外部からのインストールを許可していないなど、環境を整えるためのハードルが高いところもありますので、システム担当部署と相談しながら導入する必要があります。

SeleniumBasicのインストールが許可されない場合は、次のライブラリもあります。

 

TinySeleniumVBA

Tiny=小さい、が名称に入っているように、最小限のWeb操作ができるライブラリです。

GitHub - uezo/TinySeleniumVBA: A tiny Selenium wrapper written in pure VBA
A tiny Selenium wrapper written in pure VBA. Contribute to uezo/TinySeleniumVBA development by creating an account on Gi...

 

ブラウザのバージョンに合わせたWebDriverのインストールと、VBAで書かれたTinySeleniumVBAライブラリをインポートするだけでブラウザの操作ができます。

要素の属性nameidを指定してエレメントIDを取得し、テキストボックスに文字を入力したり、ボタンをクリックできます。XPathを指定しても操作が可能。

ただ、どうしてもやり方がわからなかったことが一点。

複数のフレームで構成されたWeb画面の操作で、別のフレーム内の要素を操作したい場合があると思います。

その場合、フレームを切り替えて操作する必要があるのですが、こちらのライブラリではフレームの切り替えをどうやってやるのかわかりませんでした。

どうしてもわからず、こちらのライブラリでの開発は断念・・・ 

 

ライブラリはインストール許可が出ない!Tinyでもやりたいことができない!となれば、もうVBA単体でWebDriverWeb操作の指示を出すしかないです。

 ※ライブラリを使ってのブラウザ操作と、使わずにブラウザ操作の実装をしてみて、当たり前ですが圧倒的にライブラリを使ったほうが開発が簡単です!ライブラリ使える環境であれば、絶対使ったほうがいいです。

 

 

VBAとWebDriverのみで実装してみる

まずはVBAからブラウザ操作をするために、環境構築からやっていきます。

 環境構築といっても、とてもシンプルで簡単です。

 

WebDriverダウンロード

ブラウザはEdge を使うので、EdgeWebDriverをダウンロードします。

Microsoft Edge WebDriver (英語) |Microsoft Edge 開発者

WebDriverにはバージョンがあり、使用するブラウザと同じバージョンのWebDriverをダウンロードする必要があります。

使用するブラウザ(Edge)のバージョンを確認します。

Edgeブラウザの[…]メニューから[設定]をクリックします。

サイドメニューの[Microsoft Edgeについて]をクリックすると、上の方にブラウザのバージョンが表示されています。

このバージョンと同じバージョンのWebDriverをダウンロードします。

先ほどのMcrosoft Edge WebDriverのサイトにアクセスします。  

下にスクロールすると[最近のバージョン]という項目があるので、そこからブラウザのバージョンと同じバージョンをダウンロードします。

バージョンがなければ、その下の[完全なディレクトリに移動]をクリックすれば、過去のバージョンをダウンロードできます。

 

JSONConverterをプロジェクトに追加

WebDriverとのやり取りは、JSONという決まったデータ形式でやり取りを行います。例えば以下のようなものがJSONで書かれたデータです。”キー”(例:”name”)と”データ”(例:”Aさん”)がセットになっています。

{ 
  "name": "Aさん",
  "gender": "女性",
  "id": "201"
}

JSONConverterは、VBAで作成したリクエストデータをJSONに変換する機能です。

VBAで書かれているため、ソースコードをダウンロードし、作成するExcelVBAのエディター内に設置するだけです。

以下からソースコードをダウンロードします。

https://github.com/VBA-tools/VBA-JSON/releases/tag/v2.3.1

 

ExcelVisualBasicEditorを開き、解凍したJsonConverter.basをインポートします。

エディターの左ウィンドウ(プロジェクトエクスプローラー)内で右クリックすると、[ファイルのインポート]が出てくるので、クリックしてJsonConverter.basを選択するとインポートされます。

 

VisualBasicEditorについて詳しくはこちら↓

VBAとは?マクロとの違いやVBA初期導入まで

VBAとは?マクロとの違いやVBA初期導入まで
VBA(Visual Basic for Applications)は、ExcelやWord、Accessといった、Microsoft Officeで使用するプログラミング言語です。 VBAはExcel内のデータ集計や、分析、SUMやAVE...

 

参照設定

VBAで作成したリクエスト情報は、こちらも”キー”と”データ”がセットになった[連想配列]オブジェクトに格納します。その連想配列オブジェクトを使えるようにするための設定をします。

[ツール]メニューの[参照設定]を開き、[Microsoft Scripting Runtime]にチェックを入れます。

連想配列の形式に沿ってVBAでリクエストデータを格納し、JSONConverterでJSON形式に変換します。

 

これで環境構築は終わりです。実装に入っていきます。

 

 

Web操作の自動化の実装

WebDriverに命令を送る方法は、以下の記事がとても参考になりました。

感謝です。

SeleniumなしでWebDriverを操作するには – Part2 (zenn.dev)

 

単純なログイン画面を操作するVBAを実装していきます。

仮に以下のような画面遷移のあるWebサイトがあるとします。

 

このページをもとに、以下の操作をVBAから指示していきます。

①ログインページにアクセスする

②ログインパスワードを入力する

③ログインボタンをクリックする

④遷移後のページの左側[メニュー1]のリンクをクリックする

 

標準モジュールを追加して実装していきます。

 

 

WebDriverの起動

まずは、WebDriverを起動させます。使用するのはShell関数です。

Shell関数について詳しくはこちら↓

Shell 関数 (Visual Basic for Applications)
Office VBA リファレンス トピック

 

Shell は外部のプログラムを実行する関数です。Shellで指定するパスは、先ほどWebDriverを格納した場所なので、ご自身の環境に合わせて設定してください。

Shell "C:¥msedgedriver\msedgedriver.exe", vbMinimizedNoFocus

WebDriverは実行時、ローカルホストで9515のポートをデフォルトで使用します。

※デフォルトポートは無くなり、接続時に以下のように9515を指定する必要があります。

Shell "C:¥msedgedriver\msedgedriver.exe --port=9515", vbMinimizedNoFocus

ポートは、コンピューターとサーバーが通信するためのドアと表現されます。ポート番号が無いと、複数稼働しているソフトウェアのどれに接続したらよいかわからなくなります。

 

 

①ログインページにアクセスする

ここから、Webブラウザに対して操作の指示をリクエストデータと一緒に出します。以下の記事の通り、WebブラウザとWebサーバー間のやり取りは、HTTP通信を使って行われます。

Webスクレイピングの基本!HTTP通信について

Webスクレイピングの基本!HTTP通信について
VBAでWebブラウザ操作を自動化するにあたって、基本的なことをまとめました。 VBAでのWebスクレイピングは初めてだったので、改めて基本的なことを学習したので、Webスクレイピングが初めての方にシンプルにお伝えできればと思います。 We...

まずは、HTTP通信を使用するための準備を行います。

 

 

HTTPクライアントの起動

HTTPクライアントを起動させます。HTTPクライアントとはHTTPリクエストを送り、レスポンスを受け取るためのツールです。ServerXMLHTTPには、HTTP通信のためのメソッドとプロパティが定義されています。

Dim httpobj As Object

Set httpobj = CreateObject("MSXML2.ServerXMLHTTP")

 

ブラウザの起動

リクエストするデータを格納するための、Dictionaryオブジェクトを作成します。Dictionaryオブジェクトは、JSONと同じく”キー”と”データ”がセットになった連想配列のオブジェクトです。

Dim edgeprm as New Dictionary

edgeprm.Add "capabilities", New Dictionary

edgeprm.Add "desiredCapabilities", Nothing

 上のリクエストデータは、ブラウザ起動のためのおまじないだと思ってください。

 

Open関数を使って、POSTでブラウザを起動するよう指示します。[/session]がブラウザ起動の命令になります。

httpobj.Open "POST", "http://localhost:9515/session"
※POSTとGETについて
HTTP通信において、リクエストを投げる方法としてPOST送信とGET送信があります。
GET送信はURLの末尾にデータを付けて送信します。送信データがアドレスバーに表示されてしまうため、パスワード入力を伴うログイン処理等には向いていません。
POST送信は、データをbody要素に記述して送信します。GET送信と違い、データの制限や外から見えることはないため、用途によって使い分けると良いです。

POSTとGETについてについて詳しくはこちら↓
Webスクレイピングの基本!HTTP通信について

 

リクエストヘッダーには「JSONでデータ送るよ」という合図を送ります。

httpobj.setRequestHeader "Content-Type", "application/json"

 

JSONに変換した連想配列のデータをリクエスト送信します。

httpobj.send JsonConverter.ConvertToJson(edgeprm)

 

 

先ほどのブラウザ起動時のレスポンスから、セッションIDの情報を抽出します。JSONで受け取っているので、VBAで利用できるように変換[.ParseJson()]してます。

Dim sessionId As String

sessionId = JsonConverter.ParseJson(httpobj.responseText)("value")("sessionId")

 

上のレスポンスは[“value”]の中の[“sessionId”]の値を指定して、セッションIDを取得しています。

 

レスポンスデータ全体を見たい場合は、上の[httpobj.responseText]をコンソールに出力してみると良いです。コンソールに出力するには[Debug.Print]を使用します。

Debug.Print httpobj.responseText

 

変更して実行後、イミディエイトウィンドウを表示させてレスポンスデータを確認します。イミディエイトウィンドウは以下から表示できます。

Edgeブラウザ起動リクエストに対するレスポンスのJSONデータです。

{
  "value":
             {
         "capabilities":
                                 {
                                    "acceptInsecureCerts":false,
                                     "browserName":"MicrosoftEdge",
                                     "browserVersion":"122.0.2365.120",
                                     "fedcm:accounts":true,
                                     "ms:edgeOptions":
                                                        {
                                                          "debuggerAddress":"localhost:54599"
                                                        },
                                      "msedge":
                                                 {
                                                   "msedgedriverVersion":"122.0.2365.113 (9bf34bfff1f4dadaf5c0315e9db820883f66aa79)",
                                                    "userDataDir":"C:\\WINDOWS\\SystemTemp\\scoped_dir18612_87488463"
                                                   },
                                      "networkConnectionEnabled":false,
                                      "pageLoadStrategy":"normal",
                                      "platformName":"windows",
                                      "proxy":
                                                {
                                                        },
                                      "setWindowRect":true,
                                      "strictFileInteractability":false,
                                      "timeouts":
                                                   {
                                                      "implicit":0,
                                                      "pageLoad":300000,
                                                      "script":30000
                                                    },
                                      "unhandledPromptBehavior":"dismiss and notify",
                                      "webauthn:extension:credBlob":true,
                                      "webauthn:extension:largeBlob":true,
                                      "webauthn:extension:minPinLength":true,
                                      "webauthn:extension:prf":true,
                                      "webauthn:virtualAuthenticators":true
                                     },
                 "sessionId":"1qaz2wsx3edc4rfv5tgb6yhn7ujm"
         }
}

ブラウザバージョンや、WebDriverバージョン等も確認できます。

ちゃんと[“value”]の中に[“sessionId”]がありますね。ブラウザ起動からWeb操作完了まで、このセッションIDを使ってWeb操作の命令を出します。

 レスポンスを確認したら、元のコードに戻しておいてください。

※セッションIDとは?
セッションとは、サイトへのアクセスの開始から終了までの通信のことです。セッションIDとは、セッションを識別するために付与されるIDのことです。

 

Webサイトへアクセス

次に、取得したセッションIDを使って、目的のWebサイトにアクセスします。

Dim accessprm as New Dictionary

accessprm.Add "url", “https://○○○○”

 

WebDriverに指示を出します。[/url]がWebサイトへアクセスするための命令になります。

httpobj.Open "POST", "http://localhost:9515/session/" + sessionId + "/url"

httpobj.setRequestHeader "Content-Type", "application/json"

httpobj.send JsonConverter.ConvertToJson(accessprm)

 

 

②ログインパスワードを入力する 

次は、Webページ内に設置してある、パスワード入力するテキストボックスへ入力の命令します。

 

Webページ内の各要素の操作

Webブラウザ操作では、サイトのページ内に設置された要素のエレメントIDを指定し、操作の指示を出します。

エレメントIDとは、各要素を特定するための固有のIDです。[/element]がエレメントIDを取得するための命令になります。

"http://localhost:9515/session/" + sessionId + "/element"

 

上記の命令と共に、要素の情報をリクエストで送ります。

要素の情報は以下のうちのどれかです。

CSS css selector
リンク文字 link text
部分リンク文字 partial link text
タグ名 tag name
XPath xpath

 

要素名やXPathの調べ方についてはこちら↓

 Webスクレイピングの基本!要素の属性とXPathの調べ方

Webスクレイピングの基本!要素の属性とXPathの調べ方
VBAでWebブラウザ操作を自動化するにあたって、基本的なことをまとめました。 今回は、Webページ内の要素を操作するときに必要な、要素の情報を調べる方法です。Webスクレイピングが初めての方にシンプルにお伝えできればと思います。 Webペ...

 

テキストの入力

Webページ内の、パスワード入力テキストボックスに文字を入力します。

まずは、入力するテキストボックスのエレメントIDを取得します。

パスワードを入力するテキストボックスの要素を、開発者ツール(F12)で見てみます。

<input>タグで囲まれている部分が、テキストボックスです。name属性に[pass]と名前が付けられています。

テキストボックスの要素名が[pass]である要素のエレメントIDを取得するために、リクエストデータを作成します。

Dim passprm As New Dictionary

    passprm.Add "using", "css selector"

    passprm.Add "value", "[name=""pass""]"

 

[/element]で命令し、リクエストデータを送信します。

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionId + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(passprm)

 

レスポンスデータから、[“value”]内の[“element-6066-11e4-a52e-4f735466cecf”]の値を抽出します。[element-6066-11e4-a52e-4f735466cecf]は、エレメントIDを取得するためのキーであり、固定値です。

    Dim elementId As String

    elementId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

取得したテキストボックスのエレメントIDに対して、文字を入力します。

    Dim pass As String

    pass = "パスワード"
 

    Dim passprmAs New Dictionary

    passprm.Add "text", pass

   
    httpobj.Open "POST", "http://localhost:9515/session/" + sessionId + "/element/" + elementId + "/value"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(passprm)

 

③ログインボタンをクリックする

ログインボタンの要素にname属性が無い場合、value属性の値でエレメントIDを取得します。

    Dim loginprm As New Dictionary

    loginprm.Add "using", "css selector"

    loginprm.Add "value", "[value=""ログイン""]"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionId + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(loginprm)

   

    Dim btnId As String

    btnId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionId + "/element/" + btnId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

 

④遷移後のページの左側[メニュー1]のリンクをクリックする

遷移後のページの左メニューにある、[メニュー1]をクリックする操作を実装します。

しかし、これまでと同じように、要素の情報からエレメントIDを取得してクリック操作・・・という手順ができないのです。

 

遷移後のページ内でフレームを切り替える

Webページの中には、分割された複数の画面を1つにまとめて構成しているものがあります。今回でいうと、遷移後の画面のようなイメージです。

開発者ツール(F12)で要素を見てみると、<frame>というタグを使用して以下のように分割されています。

フレーム分けされたページは、それぞれのフレームが別のHTMLファイルであるため、要素名や属性の指定をしてもエレメントIDが取得できません。そのため、今まで通りの手順では操作を命令できないのです。

 

遷移直後は、親フレーム内にフォーカスされています。それぞれ設置されているフレームは子フレームの扱いです。以下のようなイメージです。

親フレームから子フレームの要素を操作したいときは、子フレームにフォーカスを切り替えて処理を行う必要があります。フレームの切り替えは[/frame]で命令を送ります。

"http://localhost:9515/session/" + sessionID + "/frame"

 この命令に、どの子フレームに切り替えるかの情報を付けてリクエストデータとして送信します。

 

WebDriverに関する資料は以下を参考。

ここでフレーム切替について調べました。

WebDriver (w3.org)

 

フレーム切替のリクエストデータを作成します。要素内で<frame>タグを数えて0から何番目のフレームか確認してください。この時、<frameset>タグは無視して、上から<frame>タグのみ数えます。

リクエストデータに、切り替える子フレームを指定する[1]を格納します。

   Dim frm1 As New Dictionary

   frm1.Add "id", 1

 

/frame」で命令し、リクエストデータを送信します。

 

   httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame"

   httpobj.setRequestHeader "Content-Type", "application/json"

   httpobj.send JsonConverter.ConvertToJson(frm1)

 

切り替え後の子フレームでは、ページ左の「メニュー1」リンクテキストをクリックする操作をしてみます。

リンクテキストとは、Webページ内にボタンではなくリンクでクリックできるような要素です。「←戻る」とか「詳しくはこちらをクリック」などの例がわかりやすいでしょうか。

 

フレーム切り替えが完了したら、今までと同様エレメントIDを取得するためのリクエストデータを作成します。今回は[css selector]ではなく、[link text]を指定します。

    Dim linkprm As New Dictionary

    linkprm.Add "using", "link text"

    linkprm.Add "value", "メニュー1"

 

あとはいつも通り、エレメントIDを取得します。

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(linkprm)

 

    Dim linkId As String

    linkId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

エレメントIDを取得したら、次はクリックする処理です。[/click]で命令を出します。

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + linkId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

 

別の子フレームへの切り替えについて

 フレーム切り替えをしたら、次に別の子フレームの要素を操作したいときは一旦親フレームに戻る必要があります。子フレームから子フレームへの切り替えはできません。

 

親フレームに戻る命令は以下です。「/frame/parent」で命令するだけです。 

"http://localhost:9515/session/" + sessionID + "/frame/parent"

 

フレーム切り替えのリクエストを投げます。これで親フレームに戻ります。

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame/parent"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

 

そして、別の子フレームに切り替えて、今度はXPathでエレメントIDの取得と操作をしてみます。子フレームは0から数えて2番目のフレームに切り替えて操作します。

    Dim frm2 As New Dictionary

    Frm2.Add "id", 2

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(frm2)

   

    Dim xpathprm As New Dictionary

    xpathprm.Add "using", "xpath"

    xpathprm.Add "value", "ここにXPathが入ります"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(xpathprm)

 

    Dim xpathId As String

    xpathId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + xpathId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

 

 

XPathの取得方法はこちらです↓

 Webスクレイピングの基本!要素の属性とXPathの調べ方

Webスクレイピングの基本!要素の属性とXPathの調べ方
VBAでWebブラウザ操作を自動化するにあたって、基本的なことをまとめました。 今回は、Webページ内の要素を操作するときに必要な、要素の情報を調べる方法です。Webスクレイピングが初めての方にシンプルにお伝えできればと思います。 Webペ...

 

これで一通りのWeb操作はできたのではないでしょうか。

最後にコード全体です。同じような操作があるので、実装の際は関数化するといいです。

私は以下が参考になりました。[リクエスト処理の共通部品化]の部分です。

Excel VBAでSeleniumBasicを使わずにスクレイピングする - Qiita
こんにちは。ExcelVBAからIEを制御する本の著者であり、妹にExcelVBAからIEを制御する方法を教えてもらうゲームの作者であるうえぞうと申します。 Internet Explorerは使われる機会が減ってきたものの、Excelから...

 

Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)


Sub main()

    'WebDriver起動

    Shell "C:\EdgeWebDriver\edgedriver_win64\msedgedriver.exe --port=9515", vbMinimizedNoFocus
 

    'HTTPクライアント起動

    Dim httpobj As Object

    Set httpobj = CreateObject("MSXML2.ServerXMLHTTP")
   

    'ブラウザ起動しセッションID取得

    Dim edgeprm As New Dictionary

    edgeprm.Add "capabilities", New Dictionary

    edgeprm.Add "desiredCapabilities", Nothing

   

    httpobj.Open "POST", "http://localhost:9515/session"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(edgeprm)

   

    Dim sessionID As String

    sessionID = JsonConverter.ParseJson(httpobj.responseText)("value")("sessionId")

   

    'Webサイトへアクセス

    Dim accessprm As New Dictionary

    accessprm.Add "url", "https://○○○○"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/url"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(accessprm)

   

    'パスワード入力   

    Dim passprm As New Dictionary

    passprm.Add "using", "css selector"

    passprm.Add "value", "[name=""pass""]"

   

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(passprm)

   

    Dim passId As String

    passId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

   

    Dim pass As String

    pass = "パスワード"

 

    Dim passvalueprm As New Dictionary

    passvalueprm.Add "text", pass

   

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + passId + "/value"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(passvalueprm)

   

    Sleep 2000

   

    'ログインボタンクリック

    Dim loginprm As New Dictionary

    loginprm.Add "using", "css selector"

    loginprm.Add "value", "[value=""ログイン""]"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(loginprm)

   

    Dim btnId As String

    btnId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + btnId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

    Sleep 5000

 

    '子フレーム切替

    Dim frm1 As New Dictionary

    frm1.Add "id", 1

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(frm1)

   

    'リンクテキストで要素指定

    Dim linkprm As New Dictionary

    linkprm.Add "using", "link text"

    linkprm.Add "value", "メニュー1"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(linkprm)

 

    Dim linkId As String

    linkId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + linkId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

    Sleep 2000

 

    '親フレームに戻る

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame/parent"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

   

    '別の子フレームへ

    Dim frm2 As New Dictionary

    frm2.Add "id", 2

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/frame"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(frm2)

  

    'XPathで要素指定

    Dim xpathprm As New Dictionary

    xpathprm.Add "using", "xpath"

    xpathprm.Add "value", "ここにXPathが入ります"

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(xpathprm)

 

    Dim xpathId As String

    xpathId = JsonConverter.ParseJson(httpobj.responseText)("value")("element-6066-11e4-a52e-4f735466cecf")

 

    httpobj.Open "POST", "http://localhost:9515/session/" + sessionID + "/element/" + xpathId + "/click"

    httpobj.setRequestHeader "Content-Type", "application/json"

    httpobj.send JsonConverter.ConvertToJson(New Dictionary)

 

End Sub

 

適度にSleepを入れると動作が安定します。

 

Sleepについて
操作と操作の間にSleepを入れると、Webページの読み込み前に操作することによるエラーを回避できます。1行目にSleepを使うための宣言を書いておきます。停止時間は、Sleepの後にミリ秒単位で指定します。

1行目
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)

 

 

追記:GETを使用したWebページ内のデータ取得方法

今回は出番のなかった、Webページ内のデータの取得方法です。

Webページ内に表示されているデータを取得したい場合は、送信するリクエストデータがないので、GETリクエスト送信で行います。

’GETリクエストで命令

httpobj.Open "GET", "http://localhost:9515/session/" + セッションID+ "/element/" + エレメントID + "/property/innerHTML"

httpobj.setRequestHeader "Content-Type", "application/json"

httpobj.send    ’リクエストデータなしで送信


’取得した値を格納

Dim textValue

textValue = JsonConverter.ParseJson(httpobj.responseText)("value")

 今まで通り要素のエレメントIDを取得し、“/property/innerHTML”で命令することで、要素の値を取得できます。

 

 

 まとめ

VBAでライブラリ無しで、何とかブラウザ操作できそうということがわかりました。

PCに入れるWebDriverは、ブラウザのバージョンに合わせて更新する必要があります。処理のはじめに、ブラウザバージョンを確認し同じバージョンのWebDriverを自動でダウンロードする処理をさせれば良さそう。