2009-07-10
Excel VBAのマクロで,IEを自動操作しよう (DOMセレクタ関数をVBAで自作)
JavaScriptと同じように,VBAでもDOM操作が可能。
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
これは,独自の関数(後述)をいろいろ使って
というコード。
(※「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を使うとよいだろう。)
しかし,「ブラウザ経由の面倒なタスク」を繰り返しこなす目的には,非常に役立つ。
- (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
- 757 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLJ_jaJP244JP244&q=excel+マクロ+IE
- 713 http://www42.atwiki.jp/tomokazu0525/pages/18.html
- 170 http://www.google.co.jp/search?q=エクセル マクロ IE操作&hl=ja&lr=&sa=2
- 133 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=NYp&q=VBA+excel+IE 値を入力&btnG=検索&lr=lang_ja
- 126 http://search.yahoo.co.jp/search?p=エクセル+マクロ+IE+input+javascript&ei=UTF-8&fr=my-top-cm&x=wrt
- 124 http://www.google.co.jp/search?hl=ja&q=エクセル マクロ DOM&lr=&rlz=1R2GZEZ_jaJP333&aq=f&oq=
- 123 http://www.google.co.jp/search?client=firefox-a&rls=org.mozilla:ja:official&channel=s&hl=ja&q=VBA getElementById&lr=&btnG=Google+検索
- 111 http://www.google.co.jp/search?q=ブラウザ+Excel&ie=UTF-8&oe=UTF-8&hl=ja&client=safari
- 107 http://www.google.co.jp/search?hl=ja&lr=lang_ja&tbs=lr:lang_1ja&q=excel+ ブラウザ 検索&aq=f&aqi=&aql=&oq=&gs_rfai=
- 100 http://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=ie+マクロ+エラー&num=50