[Excel VBA]WebDriver経由でブラウザ操作（SeleniumVBA使い方メモ）

# まえがき

[SeleniumVBA](https://github.com/GCuser99/SeleniumVBA) という Excel VBA でブラウザを操作するための WebDriver のラッパー（HTTP クライアント）に触れる機会があり、そのとき覚えたことをまとめてみました。 

# 準備

## SeleniumVBA の入手

[こちら](https://github.com/GCuser99/SeleniumVBA/releases) からダウンロードできます。 

:::note info
本記事執筆時点の最新バージョンは `2.0` です。
:::

## アドイン登録

本家が Excel アドイン（SeleniumVBA.xlam）を用意してくれているので、Excel にそれを登録します。 

1. ［開発］タブ ⇒ ［Excel アドイン］ボタン ⇒ ［アドイン］ダイアログ を表示 
1. ［参照］ボタン ⇒ SeleniumVBA.xlam の格納パスに移動[^1] ⇒ SeleniumVBA.xlam を選択 
1. ［有効なアドイン］に `Seleniumvba` が追加され、チェックが入っていることを確認 

[^1]: Excel アドインのデフォルトの参照先である `%USER_PROFILE%\AppData\Roaming\Microsoft\AddIns` に SeleniumVBA.xlam を配置してしまうのもアリです

:::note info
突貫作業[^2]のときは、アドインがあることに気づかずにソース（標準モジュール、クラスモジュール）をマクロ有効ワークシート（.xlsm）にインポートして使いましたが、どちらの方法でも構わないと思います。 
ただし、ソースをインポートした場合は、SeleniumVBA のクラスの参照や初期化の方法が異なります。[^3] 
:::

[^2]: [あとがき](#あとがき) 参照
[^3]: [補足説明](#補足説明) 参照

# WebDriver の入手

操作したいブラウザの製品およびバージョンに合わせた WebDriver を入手します。 

* Edge の場合
  [Microsoft Edge WebDriver](https://developer.microsoft.com/ja-jp/microsoft-edge/tools/webdriver/)
* Chrome の場合
  [ChromeDriver](https://chromedriver.chromium.org/downloads)
* Firefox の場合
  [GeckoDriver](https://github.com/mozilla/geckodriver/releases)

Edge 用は `64bit版` も提供されていますが、Chrome と Firefox は `32bit版` だけのようです。 

ダウンロードした zip ファイルから、msedgedriver.exe / chromedriver.exe / geckodriver.exe を取り出し、任意のフォルダに配置します。 

:::note info
以降の実装サンプルは、マクロ有効ワークシート（.xlsm）と同じフォルダに配置した想定となります。 
:::

# 実装サンプル

SeleniumVBA のシンプルな使い方をサンプルコードとしてまとめました。 

:::note info
今後も可能な限り拡充予定です。 
:::

## ブラウザ起動 / 終了

起動はターゲットのブラウザごとに若干異なります。 

``` VB: Edge の場合
    Dim driver As SeleniumVBA.WebDriver
    Set driver = SeleniumVBA.New_WebDriver
    driver.StartEdge ThisWorkbook.Path & "\msedgedriver.exe"
    driver.OpenBrowser
```
``` VB: Chrome の場合
    Dim driver As SeleniumVBA.WebDriver
    Set driver = SeleniumVBA.New_WebDriver
    driver.StartChrome ThisWorkbook.Path & "\chromedriver.exe"
    driver.OpenBrowser
```
``` VB: Firefox の場合
    Dim driver As SeleniumVBA.WebDriver
    Set driver = SeleniumVBA.New_WebDriver
    driver.StartFirefox ThisWorkbook.Path & "\geckodriver.exe"
    driver.OpenBrowser
```

終了は共通です。 

``` VB: ブラウザ終了
    driver.CloseBrowser
    driver.Shutdown
```

## ページ移動

指定した URL にページ移動したい場合は、以下のようになります。 

``` VB: ページ移動
    driver.NavigateTo "<url>"
```

:::note info
`進む（GoForward）` や `戻る（GoBack）`、`再読み込みする（Refresh）` こともできます。 
:::

## 要素検索

ページ内の要素は `ID` `クラス名` `CSS セレクタ` `XPath` などの指定によって検索できます。 

``` VB: ID 指定
    Dim element as WebElement
    Set element = driver.FindElementByID("<id>")
```

``` VB: クラス名指定
    Dim element as WebElement
    Set element = driver.FindElementByClassName("<class_name>")
```

``` VB: CSS セレクタ指定
    Dim element as WebElement
    Set element = driver.FindElementByCssSelector("<css_selector>")
```

``` VB: XPath 指定
    Dim element as WebElement
    Set element = driver.FindElementByXPath("<xpath>")
```

:::note info
上記以外にも `名前（Name）` `リンクのテキスト（LinkText）` `タグ名（TagName）` などの指定でも検索可能です。 
:::

## クリック

あっさりしています。 

``` VB: クリック
    element.Click
```

## キー入力

入力フィールドへの入力や書き換えは、対象の要素にキー入力を送ることで実現します。 

``` VB: キー入力
    element.SendKeys "<入力文字列>"
```

:::note warn
キー入力は **1 度にまとめて渡す** 必要があります。（複数回に分けて渡すと **毎回上書き** され、最後の文字列だけが残ります） 
また、`Enter キー` を入力したい場合[^4]は、`vbCrLf` を末尾に付与します。 
ちなみに、要素の属性（`value` や `text` など）を変更しても、そのままでは画面には反映されません。（属性の状態を監視して変更を画面に反映させるフレームワークを利用した Web サイトであれば、画面にも反映されると思います） 
:::

[^4]:Submit に相当するボタンがなく、Enter キー押下のイベントハンドラで Post 送信を行うような UI 設計の場合に必要になります

## リスト選択

リストの選択は `インデックス` `値` `表示テキスト` のいずれかの指定によって行います。 

``` VB: インデックス指定
    element.SelectByIndex <index>
```

:::note info
リストの先頭のインデックス番号は `1` です。 
:::

``` VB: 値指定
    element.SelectByValue "<value>"
```

``` VB: 表示テキスト指定
    element.SelectByVisibleText "<表示文字列>"
```

## フレーム切替

フレームが入れ子になった html を操作する場合は、操作対象を含んだ `<iframe>` の要素を指定してフレームを切り替える必要があります。 

``` VB: フレーム切替
    Set element = driver.FindElementByID("<iframe_id>")
    driver.SwitchToFrame element
```

## ウェイト

WebDriver はブラウザと同期しているわけではないので、適宜ウェイトを挟んで操作タイミングを調整する必要があります。 

``` VB: ウェイト
    driver.Wait 3000
```

## スクリーンショット

簡単にスクリーンショットを取ることができます。 

``` VB: スクリーンショット
    driver.SaveScreenshot "<保存ファイル名>"
```

:::note info
スクリーンショット以外にも、`HTML 保存` や `PDF 出力` も可能です。 
ただし、`PDF 出力` は `ヘッドレスモード` でしか利用できないようです。 
:::

## まとめ（サンプル）

Edge を自動操作して [Yahoo! JAPAN の乗換案内](https://transit.yahoo.co.jp/) で **「東京」から「新宿」へ「最安」の「終電」で移動する場合** の乗換の検索を行うサンプルはこんな感じになります。 

``` VB: 乗換案内
Option Explicit

Public Sub Main()

    Dim driver As SeleniumVBA.WebDriver
    Dim element As WebElement

    Set driver = SeleniumVBA.New_WebDriver

    'ブラウザ（Edge）起動
    driver.StartEdge ThisWorkbook.Path & "\msedgedriver.exe"
    driver.OpenBrowser

    'Yahoo! JAPAN 路線情報
    driver.NavigateTo "https://transit.yahoo.co.jp/"

    '表示待ち（適宜調整）
    driver.Wait 1000

    '出発：東京
    Set element = driver.FindElementByName("from")
    element.SendKeys "東京"

    '到着：新宿
    Set element = driver.FindElementByName("to")
    element.SendKeys "新宿"

    '日時：終電
    Set element = driver.FindElementByID("tsLas")
    element.Click

    '表示順序：料金が安い順
    Set element = driver.FindElementByID("s")
    element.SelectByVisibleText "料金が安い順"

    '検索ボタンクリック
    Set element = driver.FindElementByID("searchModuleSubmit")
    element.Click

    '表示待ち、兼、一時停止（適宜調整）
    driver.Wait 5000

    '結果保存
    driver.SaveScreenshot ThisWorkbook.Path & "\ルート、運賃検索結果.png"
    driver.SaveHTMLToFile driver.GetPageSource, ThisWorkbook.Path & "\ルート、運賃検索結果.html"

    'ブラウザ終了
    driver.CloseBrowser
    driver.Shutdown

    End

End Sub
```

# 補足説明

## Excel アドインではなくソースをインポートした場合の差異

:::note
T.B.D. 
:::

# あとがき

:::note alert
もともと [まえがき](#まえがき) として書いたものですが、読み手にとっては **時間の無駄でしかない内容** だと気づいたので途中で移動させました。 
興味のあるかただけお読みください。 
:::

とあるヘルプデスク業務の支援で、**ブラウザを自動操作して定型作業を効率化するツール** を作ってほしい、という要望に対応することになりました。 
このご時世なら Web API を叩くなり、Power Automate あたりでちゃちゃっと（？）作れたりするはずですが、**環境上の制約（お約束？）** でまさかの Excel VBA で作ることに。 

ターゲットのブラウザが IE ならサンプルはいくらでも見つかるのですが、今回のターゲットは Edge（Chromium）でした。 
ググってみても **直接制御は実質不可能**という結論ばかり[^5]が見つかり、どうしたものかと途方に暮れかけていたところ、 [SeleniumBasic](http://florentbr.github.io/SeleniumBasic/) という VB.NET / VBA / VBScript から Selenium の WebDriver を扱えるようにしたフレームワークを見つけました。 

コレならいけそうと飛びついてみたものの、原因不明のエラーが出て Edge が起動できないうえ、そもそも ヘルプデスク用の端末に **SeleniumBasic をインストールできないかもしれない**（手続きのハードルが高く、即時性に欠ける）、という問題にブチ当たり早くも頓挫しかけます。 

そこで今度は ~~SeleniumBasic の前身である~~ Excel アドイン（およびソース）形式で提供されている SeleniumVBA に目を付けました。 
こちらだと Edge の起動はあっさりできたのですが、目的の Web サービスに接続する手前の認証サービス（SSO）をパスするところから **躓きの連続** で、ひとつひとつ手探り[^6]で解決していくことになりました。 

といった紆余曲折を経て、なんとかツールの完成にこぎつけました（が、納期[^7]はまったく守れませんでした）。 

以上をふまえて、**需要はほとんどなさそう**[^8] ですが、自身の備忘も兼ねて SeleniumVBA の使い方をざっくりまとめてみることにしました。 

[^5]:“ウィンドウハンドルを指定してHTMLDocumentを捕まえる方法”で頑張ればできなくはない、という [記事](https://www.ka-net.org/blog/?p=6033) は見つけたのですが、これはこれでなかなか泥臭くもあり。。。
[^6]:そもそも Excel VBA から WebDriver を介してブラウザ操作というのがニッチなのか、ネットでもほとんど情報が見つからず。。。
[^7]:当初は「シフト勤務で 21:00 に着手して 6:00 までに完成してほしい」と言われましたが、結局ほぼ 3 日かかりました。。。
[^8]:もしかすると誰か 1 人くらいの役には立てるかもしれない、と思いたい。。。