Excelで使えるWebサイト操作用RPA （ExcelVBA + SeleniumBasic）

リンクラフトのレトロゲーム愛好家こと @hayasakasakas です！
早いもので **[LINCRAFT Advent Calendar 2023](https://qiita.com/advent-calendar/2023/lincraft "LINCRAFT Advent Calendar 2023")** も、もう１５日目です。

今回は、今更ですが VBA についての記事です。
私は未だに一日二日で自分以外の作業を自動化する必要がある時などによく使いますが、皆さんはいかがでしょうか？

:::note
# こんな方にオススメの記事です
- **RPAで作業を楽にしたい！**
- プログラムが書けない人でもRPAシナリオを作れるようにしたい！
- 予算が無くて外部サービスが利用できない。。。
- **でも、Excelならある！！！**
:::

# はじめに 
最近、**RPA** や **AI** など、機械に作業をやってもらうことが当たり前になってきました。
そこで、今回は非エンジニアにも親和性の高い Excel でシナリオを作成しWebページを操作するRPAを作ってみようと思いました。
需要は限定的ですが、きっと刺さる人はいるはず。。。

# ゴール
テスターの方や営業の方などプログラムを書くことができない人でも、
ちょっとしたレクチャーだけで気軽にExcelだけでWeb操作RPAを作れるようにすることです。

### 完成イメージ
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/43394dbb-c186-0941-7648-38d6a318f56b.png">

# 事前準備
このVBAマクロを実行するためには以下のアプリケーションが必要です。
- SeleniumBasic
- .NET Framework
- ChromeDriver


## SeleniumBasic
### ダウンロード
- ↓ のページから `SeleniumBasic-2.0.9.0.exe` をダウンロードする
https://github.com/florentbr/SeleniumBasic/releases
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/b7c52550-d293-42d8-bbfd-4e6494a2bc0f.png">

### インストール
- `SeleniumBasic-2.0.9.0.exe` を実行する
- コンポーネント選択画面では`WebDriver for Chrome`を選択すること
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/3af6f2a2-88ec-ccbc-ed1a-36886eb5008a.png">

- 確認画面でインストール先を控えておく（後で使う）
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/3cfbdcb0-1a23-c16c-5d2c-5fd1166f1c1c.png">

- それ以外の部分はそのまま`next`を押してOK

## .NET Framework

### インストール
SeleniumBasicのインストールフォルダ内にある`StartChrome.vbs`を実行することで、`.NET Framework`をインストールすることができます。
「[インストールフォルダ]\SeleniumBasic\Scripts\StartChrome.vbs」

## ChromeDriver
### ダウンロード
- ↓ のページからGoogle Chromeのバージョンに合わせた安定版（stable）をダウンロードする
https://googlechromelabs.github.io/chrome-for-testing/

### インストール
ダウンロードしたZipファイルの中から`chromedriver.exe`を取り出して
SeleniumBasicのインストールフォルダ 「[インストールフォルダ]\SeleniumBasic」に上書きコピーする。
※ 旧バージョンのドライバを残したい場合は、バックアップを取ってから実行してください


# 作ってみましょう！
## Excel から Visual Basic を開く
- `Visual Basic`ボタンを押下する
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/16cc8d9d-50f7-80c8-46ce-4920a951fb3e.png">

- Visual Basic ウィンドウが開かれる
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/3b0a0da5-8a12-bccf-920b-53ba537e9c95.png">


- `Microsoft Excel Objects`を右クリックし、`挿入 > 標準モジュールを選択する
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/2ab4114b-2979-c28e-4da5-1cf59b10191a.png">


- Module1モジュールが作成される
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/3c286d97-2058-df3b-07e9-cbcb8935f8de.png">



## コード
以下のコードをモジュールのソースエディタに貼付します。
``` vb:Module1.bas
'Chromeドライバの読み込み
Dim driver As New Selenium.ChromeDriver

'RPAマクロのメインルーチン
Sub runRPA()

    'シートを変数化
    Dim sheet As Worksheet
    Set sheet = Worksheets("Sheet1")
    
    'ループ内で利用する変数
    Dim rowIndex As Long
    Dim actionNo As Integer
    Dim value1 As String
    Dim value2 As String
    Dim value3 As String
    
    '2行目から始める
    rowIndex = 2
    
    'A列が空になるまで１行ずつ処理する
    While sheet.Cells(rowIndex, 1).value <> ""
    
        'ワークシートの値を取り込む
        actionNo = sheet.Cells(rowIndex, 1).value
        value1 = sheet.Cells(rowIndex, 3).value
        value2 = sheet.Cells(rowIndex, 4).value
        value3 = sheet.Cells(rowIndex, 5).value
        
        '操作番号ごとに動作を変える
        Select Case actionNo
            Case 1
                'ブラウザを起動する
                Call openBrowser
            Case 2
                'ブラウザを終了する
                Call closeBrowser
            Case 3
                'ページを開く
                Call openURL(value1)
            Case 4
                'ボタンを押す
                Call clickButton(value1, value2)
            Case 5
                '入力する
                Call inputText(value1, value2, value3)
            Case 6
                'スクリーンショットを取る
                Call saveScreenShot(value1)
        End Select
        
        rowIndex = rowIndex + 1
    Wend
    
End Sub

'ブラウザ（Selenium）起動
Private Sub openBrowser()
    Call driver.Start
End Sub

'ブラウザ（Selenium）の終了
Private Sub closeBrowser()
    Call driver.Quit
End Sub

'ブラウザで引数のURLを開く
Private Sub openURL(ByVal url)
    Call driver.Get(url)
End Sub

'表示中のページのテキストボックスに文字を入力する
Private Sub inputText(ByVal targetType, ByVal key, ByVal value)

    '指定方法（ID or NAME）に合わせて利用する関数を変え、入力処理を実施する
    If targetType = "ID" Then
        Call driver.FindElementById(key).SendKeys(value)
    ElseIf targetType = "NAME" Then
        Call driver.FindElementByName(key).SendKeys(value)
    End If
    
    'JavaScriptの動作を待つ
    Call driver.Wait(50)
    
End Sub

'表示中のページのボタンを押下する
Private Sub clickButton(ByVal targetType, ByVal key)
    '指定方法（ID or NAME）に合わせて利用する関数を変え、ボタン押下処理を実施する
    If targetType = "ID" Then
        Call driver.FindElementById(key).Click
    ElseIf targetType = "NAME" Then
        Call driver.FindElementByName(key).Click
    End If
End Sub

'表示中ページのスクリーンショットを引数のパスに保存する
Private Sub saveScreenShot(ByVal path)

    Dim width As Integer
    Dim height As Integer
    
    width = driver.ExecuteScript("return document.body.scrollWidth")
    height = driver.ExecuteScript("return document.body.scrollHeight")
    Call driver.Window.SetSize(width, height)
    
    driver.takeScreenShot.SaveAs path
End Sub
```

## コード解説

### ChromeDriver のインスタンス化
``` vb:Module1.bas
Dim driver As New Selenium.ChromeDriver
```
Choromeドライバを読み込みます。
別のブラウザを使いたい場合は、それに合わせたドライバを読み込ませる必要があります。

### ブラウザを起動する処理
``` vb:Module1.bas
driver.Start
```
この１行だけでブラウザが起動します。
ブラウザはどのページにもアクセスしていない、真っ白な状態になります。

### ブラウザを終了する処理
``` vb:Module1.bas
driver.Quit
```
この１行だけで、ブラウザが終了します。

### ページを開く処理
``` vb:Module1.bas
driver.Get "https://www.google.com"
```
GET関数に URL を指定することで対象URLのページに遷移します。
関数名の通りGETリクエストで送信されます。

### ボタンを押す処理
``` vb:Module1.bas
driver.FindElementByID(key).Click
```
HTMLのID属性を指定して、ボタンをクリックします。

``` vb:Module1.bas
driver.FindElementByName(key).Click
```
HTMLのName属性を指定して、ボタンをクリックします。

### フォーム入力する処理
``` vb:Module1.bas
Call driver.FindElementById(key).SendKeys(value)
```
HTMLのID属性を指定して、値を設定します。

``` vb:Module1.bas
Call driver.FindElementByName(key).SendKeys(value)
```
HTMLのName属性を指定して、値を設定します。


### スクリーンショットを取る処理
``` vb:Module1.bas
width = driver.ExecuteScript("return document.body.scrollWidth")
height = driver.ExecuteScript("return document.body.scrollHeight")
Call driver.Window.SetSize(width, height)

driver.takeScreenShot.SaveAs path
```
`ExecuteScript`関数でJavaScriptを実行しています。
JavaScriptの内容はそれぞれ、縦と横のHTMLの画面サイズを取得し、
`Windows.setSize`関数でウィンドウサイズを変更します。
※ 希望のサイズがある場合は数値を指定してもOKです。

最後の`takeScreenShot.SaveAs`関数で対象のパスにスクリーンショットを保存しています。

# ワークシートを作成する
## マクロ実行用のシートを作成する
今回は画像のようなインターフェースにしました。
青いセルの部分を利用者に入力してもらう想定です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/43394dbb-c186-0941-7648-38d6a318f56b.png)


## 図形にマクロを登録する
エクセルでは図形や画像などにマクロを登録することができます。
今回は前述のモジュールで実装した、`runRPA`を登録します。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/2e6dafca-bd24-2c21-2149-6c627138f0c6.png">
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/5a30229d-bb30-21cc-e58d-f4e8ef508626.png">
これでワークシート側の準備は完了です。


# 動かしてみる
RPAスタートボタンを押下すると、

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/43394dbb-c186-0941-7648-38d6a318f56b.png">

自動でブラウザが立ち上がり、エクセルに記述した通りの動作が自動で行われ、
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/6da7f400-d814-e26b-f891-8fd3dca57715.png">

指定のファイルパスにスクリーンショットを保存することができました。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636185/86ea1b12-f71e-ddcb-a491-2a55f14575a4.png">


# さいごに
今回は簡単なプログラムでしたが、それなりに手を入れれば、
以下のようなユースケースで効果を発揮するので、役に立つシチュエーションが想像しやすいと思います。
- テスト仕様書(Excel)の自動実行
- テストサイトのエビデンス作成の補助（主にスクリーンショットの自動化）
- API がないサービスの自動データ入力
- いろんなサイトのスクリーンショットを集めたい

プログラムが書ける人はSelenium自体が色々な言語で利用できるので、あえてVBAでやる必要性は薄いのですが、利用者が慣れたUIで操作できることを考慮すれば、選択肢の一つになるのではないでしょうか？
ExcelVBA なので他のExcelドキュメントと連携しやすいのもメリットですね。

それでは、機会があればまたお会いしましょう！
良いエンジニアライフを！！




-----------

一緒に働く仲間を募集中です！
リンクラフト株式会社では、組織拡大に伴い積極的な採用活動を行っています。
少しでも興味がある方はぜひご連絡ください。
▽会社ホームページ
https://lincraft.co.jp/
▽Instagram
https://www.instagram.com/lincraft.inc/
▽ご応募はこちらより
https://lincraft.co.jp/recruit
※カジュアル面談も受付中です。ご希望の方はHPのお問い合わせフォームよりご連絡ください。

-----------