Excel VBAのマクロで,IEを自動操作しよう (DOMセレクタ関数をVBAで自作)
JavaScriptと同じように,VBAでもDOM操作が可能。
下記のようなマクロで,IEを操作できる。
Sub Googleで検索() ' IEを立ち上げて Google を開く Dim ie As Object Set ie = new_ie("http://www.google.co.jp") ' 検索キーワードを入力 type_val ie, "q", "ホゲラッチョ" ' 検索ボタンクリック submit_click ie, "btnG" ' 検索結果の 1 件目のタイトルを表示 MsgBox domselec(ie, Array( _ "id", "res", _ "tag", "li", 0, _ "tag", "h3", 0 _ )).innerText ' IEを閉じる ie.Quit Set ie = Nothing End Sub
これは,独自の関数(後述)をいろいろ使って
- IEを立ち上げ,
- Googleで特定のキーワードで検索を行ない,
- 検索結果の1件目のサイト名を表示する。
というコード。
(※「domselec」というDOMセレクタ関数を自作している。
jQueryの$()やprototype.jsの$$()の簡易版と思えばよい。)
下記で,この方法を解説する。
素の関数を使う場合
WebページのHTMLにアクセスするための基本的な関数は,VBAにデフォルトで備わっている。
それらを使って,冒頭のコードを工夫しないで書くと下記のようになる。
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Sub IE操作() ' IE起動 Set ie = CreateObject("InternetExplorer.Application") ie.Navigate "http://www.google.co.jp/" ie.Visible = True waitIE ie ' 検索キーワードを入力 ie.Document.getElementById("q").Value = "ホゲラッチョ" ' IEのgetElementByIdはnameも参照する Sleep 100 ' 検索ボタンクリック ie.Document.all("btnG").Click waitIE ie ' 1件目のサイトのタイトルを表示 MsgBox ie.Document.getElementById("res") _ .getElementsByTagName("li")(0) _ .getElementsByTagName("h3")(0) _ .innerText ' 制御を破棄 ie.Quit Set ie = Nothing End Sub ' IEがビジー状態の間待ちます Sub waitIE(ie) ' http://www.excel.studio-kazu.jp/kw/20070219032632.html ' http://www.ken3.org/cgi-bin/group/vba_ie.asp#Document_ReadyState_Busy Do While ie.Busy = True Or ie.readystate <> 4 DoEvents Loop Sleep 100 End Sub
JavaScriptと同じように
- getElementById
- getElementsByTagName
- getELementsByName
などの関数が使える。
また,要素に対して
- .Value
- .Click
のようにして値のアクセスとか操作を実行できる点もJavaScriptと同じ。
もっと楽にコーディングしたい
前項のコードをもっと簡潔に書くために,IE自動操作用の関数ライブラリを作ろう。
その場合,冒頭のコードと同じように,下のように書くことができる。
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Sub IE操作改() Dim ie As Object Set ie = new_ie("http://www.google.co.jp") ' 検索キーワードを入力 type_val ie, "q", "ホゲラッチョ" ' 検索ボタンクリック submit_click ie, "btnG" ' 1件目のサイトのタイトルを表示 MsgBox domselec(ie, Array( _ "id", "res", _ "tag", "li", 0, _ "tag", "h3", 0 _ )).innerText ' 終了 ie.Quit Set ie = Nothing End Sub ' IEがビジー状態の間待ちます Sub waitIE(ie) Do While ie.Busy = True Or ie.readystate <> 4 DoEvents Loop Sleep 100 End Sub ' 新規IE作成 Function new_ie(home_url) Dim ie As Object Set ie = CreateObject("InternetExplorer.Application") ' 初期ページを開く goto_url ie, home_url ie.Visible = True Set new_ie = ie End Function ' URL移動 Sub goto_url(ie, url) ie.Navigate url waitIE ie End Sub ' $ Function gid(ie, dom_id) ' 注:IEのgetElementByIdはnameも参照する Set gid = ie.Document.getElementById(dom_id) End Function ' getElementsByTagName Function gtn(parent, tag_name) Set gtn = parent.getElementsByTagName(tag_name) End Function ' 入力します Sub type_val(ie, dom_id, val) gid(ie, dom_id).Value = val Sleep 100 End Sub ' 送信ボタンやリンクをクリック Sub submit_click(ie, dom_id) gid(ie, dom_id).Click waitIE ie End Sub ' 簡易DOMセレクタ Function domselec(ie, arr) Dim parent_obj As Object Dim child_obj As Object Set parent_obj = ie.Document ' 条件配列内で階層を深めていく cur = 0 continue_flag = True Do While continue_flag = True ' 適用メソッドの種類を判定 If arr(cur) = "id" Then ' getElementById dom_id = arr(cur + 1) Set child_obj = parent_obj.getElementById(dom_id) ' 条件配列内のカーソルを進める cur = cur + 2 ElseIf arr(cur) = "tag" Then ' getElementsByTagName tag_name = arr(cur + 1) index_num = arr(cur + 2) Set child_obj = parent_obj.getElementsByTagName(tag_name)(index_num) ' 条件配列内のカーソルを進める cur = cur + 3 End If ' 取得したオブジェクトを次の階層の親オブジェクトとする Set parent_obj = child_obj ' 条件配列の終端まで来たか If cur > UBound(arr) Then continue_flag = False End If Loop Set domselec = parent_obj End Function
こうすれば,トップの IE操作改() のメソッド中には,目的機能に特化したコードのみを記述すればよくなる。
解説:
- オブジェクトの代入は,Setを付けないと実行時エラーになる。
応用
IE限定なので,開発時にはテストには利用しづらい。
(※Webアプリケーションをブラウザ上で自動テストするには,Exceleniumを使うとよいだろう。)
しかし,「ブラウザ経由の面倒なタスク」を繰り返しこなす目的には,非常に役立つ。
特に,ブラウザをExcelと連携させたい場合。
- (1)Excel上に大量のデータが書いてあって,
- (2)その大量のデータをもとに,Webサイトを操作したい
という時,VBAで解決できる。
あるいは,「Web上に大量のデータがあって,それをExcelに保存したい(=Webスクレイピング)」という用途にもぴったりだ。
(1)は,「シート上のデータをセルごとに読み込む」という事だから,VBAの定番だ。
(2)は,JavaScriptの得意分野。
だから,今回のようにVBAをJavaScriptのように使う事ができるようにしておけばよいというわけだ。
補足
他の役立つ関数。
' 要素をクリックします Sub ie_click(ie, dom_id) gid(ie, dom_id).Click Sleep 100 End Sub ' チェックボックスの状態をセットします Sub set_check_state(ie, dom_id, checked_flag) ' 希望通りのチェック状態でなければクリック If Not(gid(ie, dom_id).Checked = checked_flag) Then ie_click ie, dom_id End if End Sub ' セレクトボックスを文言ベースで選択します Sub select_by_label(ie, dom_id, label) If Len(label) < 1 Then Exit Sub End If Set opts = gid(ie, dom_id).Options For i = 0 To opts.Length - 1 ' textが同じか If opts(i).innerText = label Then opts(i).Selected = True Exit Sub End if Next i End Sub ' ラジオボタンを値ベースで選択します Sub select_radio_by_val(ie, post_name, value) If Len(value) < 1 Then Exit Sub End If Set radios = ie.Document.getElementsByName(post_name) For i = 0 To radios.Length - 1 If radios(i).Value = CStr(value) Then radios(i).Click Sleep 100 End If Next i End Sub
追記
2012年12月現在,IEで閲覧した際のGoogleトップページの仕様が変わっている。
そのため,ここで取り上げたコードは下記のように書きなおす必要がある。
' 検索キーワードを入力 type_val ie, "lst-ib", "ホゲラッチョ" ' 検索ボタンクリック submit_click ie, "btnG"
関連エントリー:
ブラウザのビジー状態を判定するための,より良い方法 (WSHでIEを自動操作する際,COMのアプリケーションイベントを利用する)
http://language-and-engineering.hatenablog.jp/entry/20100410/p1
ドキュメント作成を楽にするための,Excel VBA 頻出8パターン
http://language-and-engineering.hatenablog.jp/entry/20090401/p1
JScript / VBScript (WSH)で,IEを自動操作しよう
http://language-and-engineering.hatenablog.jp/entry/20090713/p1
[IEの自動操作]記事一覧
http://d.hatena.ne.jp/language_and_en...