May 11, 2014

IEをVBScriptから自動操作する

いろんなウェブサイトのログインや毎回PCを立ち上げる度に行っているInternet Explorerの操作があるならば、今すぐバッチファイルを作るといいでしょう。
テキストファイルを直打ちするだけで簡単に作ることができるし、一度作ってしまえば、次からそのファイルを実行するだけで作業が済んでしまいます。

以下では、WSH/VBScriptを用いたIEの自動化についてまとめます。



バッチファイルの基本

テキストエディタを開いて以下のコードを記入します。
hello.vbsというファイル名で保存してあと、ダブルクリックして実行すると、メッセージボックスが表示されるはずです。
開発の基本はこれだけです。
MsgBox "Hello!"

IEを起動する

CreateObject関数を使用します。
IEアプリケーションを起動し、それを操作するためにCreateObject関数の返り値を変数に保存しておきます。
起動直後は不可視状態になっているため、VisibleプロパティをTrueに設定し、表示します。
startIE

Sub startIE
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = True
End Sub

URIを指定して開く

先ほど起動したIEにURIを指定してwebページを開きます。NavigateメソッドにURIを指定することで、ブラウザを直接操作するときと同じようにwebページを開くことが出来ます。
openURI

Sub openURI
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = True
    
    ie.Navigate "http://www.google.co.jp"
End Sub

テキストを入力したり、ボタンを押したり

開いたwebページに対しては、Documentオブジェクトを介して通常のDOM操作が可能です。Document.all / Document.getElementById / Document.getElementsByTagNameなどのメソッドを使って目的のオブジェクトを指定できます。
値を入力する場合にはValueプロパティへ代入し、クリックする場合にはClickメソッドを使うと操作が自動化できます。
以下の例では、googleのトップページを開き、検索ワードを入力して検索ボタンを押しています。
InputAndClick

Sub InputAndClick
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = True

    ie.Navigate "http://www.google.co.jp"
    WScript.Sleep 1000

    ie.Document.getElementById("gbqfq").Value = "yahoo"
    ie.Document.getElementById("gbqfba").Click
End Sub

実行待ちを行う

前項のように、例えば、あるページを読み込んで、そのあとに読み込まれたボタンをクリックする、というバッチファイルを作りたい場合は、ページの読み込みを待たなくてはなりません。もし、読み込みを待たずにクリックを命令してしまうとボタンが無い、というエラーが発生します。

Sleepステートメントを使うこともできるのですが、必要な待ち時間はPCの性能やその時の処理の重さにより変わるため、適切な待ち時間をあらかじめ指定することは困難です。

そこで、読み込みを待つためのコードを追加します。
以下のコードでは、IEの状態を100msごとに監視し、処理が終わるまでスクリプトの実行を一旦停止し待機します。
InputAndClick

Sub InputAndClick
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = True

    ie.Navigate "http://www.google.co.jp"
    waitIE ie

    ie.Document.getElementById("gbqfq").Value = "yahoo"
    ie.Document.getElementById("gbqfba").Click
End Sub

Sub waitIE(ie)
    Do While ie.Busy = True Or ie.readystate <> 4
        WScript.Sleep 100
    Loop
    WScript.Sleep 100
End Sub

複数のオブジェクトを処理する方法

Document.getElementsByTagNameメソッドは複数のオブジェクトを返します。そこでオブジェクトを順番に処理したい場合は、setステートメントを使って配列変数として取得したり、for eachループで操作したりできます。
multipleObject

Sub multipleObject
    Set ie = CreateObject("InternetExplorer.Application")
    ie.Visible = True

    ie.Navigate "http://www.google.co.jp"
    waitIE ie

    Set DOMObjectArray = ie.Document.getElementsByTagName("div")
    MsgBox DOMObjectArray(0).innerHTML

    For Each DOMObject In ie.Document.getElementsByTagName("div")
        MsgBox DOMObject.innerHTML
        Exit For
    Next
End Sub

Sub waitIE(ie)
    Do While ie.Busy = True Or ie.readystate <> 4
        WScript.Sleep 100
    Loop
    WScript.Sleep 100
End Sub

実行中の途中経過を表示する

バッチの最初の方でVisibleプロパティをTrueとしておけば処理が進む様子が順次表示されるのですが、見ていてあまり美しくない、という場合は、スクリプトの最後でVisibleをTrueとすればよいでしょう。

ただし、この場合はスクリプトが動作しているのかどうか、が分かりにくいという欠点があります。
そこで、以下のようなコードで実行状況を表示してもよいでしょう。

VBScript Tips (Tips0169)
http://www.whitire.com/vbs/tips0169.html

読み込まれたページの状況を把握する

スクリプトによっては、スクリプトを実行する前の状況によって、結果が異なってしまう場合があります。例えば、ログインしようとしたら、スクリプト実行前のログイン状態が残っていて、強制ログインをしないとログインできない場合が考えられます。
実行後のwebページの内容をDocumentオブジェクト以下DOMを操作して調べてやります。
例えば、特定のdivの内容や、ページのタイトルを調べれば、状況が把握できるでしょう。

DOMオブジェクトが存在するか確認する

前項のようにwebページの状況を確認したい場合に、ページの状況に依存して存在したりしなかったりするオブジェクトがある場合は、エラー処理が必要になります。
例えば以下のコードでは、ボタンAが存在すればクリックし、存在しない場合は別のボタンBをクリックしています。
CheckAndClick

Sub CheckAndClick
    On Error Resume Next
        ie.Document.getElementById("ButtonA").Click
        If Err.Number <> 0 Then
            ie.Document.getElementById("ButtonB").Click
        End If
    Err.Clear
End Sub

そもそも画面を表示しなくてもいい場合(WinHTTP)

IEオブジェクトを生成すると、PCの負荷も大きくスクリプトが遅くなってしまいますし、単に文字情報を取りたい場合などは、IEオブジェクトではなくWinHTTPオブジェクトを利用することができます。
(他にもMSXMLやMSHTMLを使ったり、単にダウンロードする方法もあります。Googleで検索すると色々出てくる。)

以下のソースでは、WinHTTPRequestを使って、GoogleのトップページをResponseTextに取得し、それを表示しています。
withoutGUI

Sub withoutGUI
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    With http
        .Open "GET", "http://www.google.co.jp/", False
        .Send

        MsgBox .ResponseText
    End With
End Sub

関連記事:
セルに記入したダウンロード先の一覧を使って直接ダウンロードする応用例はこちら
Excel VBAで指定したフォルダにデータを自動でダウンロードして保存する

取得したHTMLファイルをDOMで操作する

 前項ではWinHTTPを使って、指定したURIからHTML文書をメモリに読み込むことができました。しかし、実際にダウンロードした場合は、さらに加工することが目的でしょう。

こういう場合にはhtmlfileオブジェクトが利用できます。次のサンプルではgoogleのトップページをダウンロードし、htmlfileオブジェクトに読み込ませて、DOM操作により内容を取り出しています。

DOMAccess

Sub DOMAccess
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    Set html = CreateObject("htmlfile")
    With http
        .Open "GET", "http://www.google.co.jp/", False
        .Send
        
        html.write(.ResponseText)
        MsgBox html.body.innerHTML
        'html.getElementById(), html.getElementsByTagName()なども使える
    End With
End Sub

ダウンロード結果をファイルに結果を保存する

WinHTTPでダウンロードした結果をそのままファイルに保存したい場合もあるでしょう。ADODB.Streamオブジェクトを使うと、WinHTTPで取得した内容をファイルに保存することが出来ます。


留意点は以下の通りです。
  • WHS環境ではadTypeTextが上手く機能しない(以下の例のように無理やりBinaryで処理できる場合は問題にならない)。
  • SaveToFileに指定するファイル名は保存先のパーミッションに注意する(PC環境によってはCドライブ直下に書きこめない場合があり、"コード:800a0bbc ファイルへ書き込めません"とエラーが発生する。
  • adSaveCreateNotExistは同名ファイルが存在していた場合、エラーを返す。
次のサンプルでは、googleのトップページをtext.txtに保存します。
WinHTTPのResponseBodyプロパティ には、取得した内容がStream形式で格納されるので、これをADODB.StreamオブジェクトにWriteメソッドで書き込みます。書き込みが終 わったらSaveToFileメソッドでストリームをファイルに保存しています。

saveToFile

Sub saveToFile
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    With http
        .Open "GET", "http://www.google.co.jp/", False
        .Send
    End With

    With CreateObject("ADODB.Stream")
        .Type = 1 'adTypeBinary
        .Open
        .Write http.responseBody
        .SaveToFile "c:\test.txt", 1 '1:adSaveCreateNotExist, 2:adSaveCreateOverWrite
        .Close
    End With
End Sub

参考

InternetExplorer object (Windows)
http://msdn.microsoft.com/en-us/library/aa752084(v=vs.85).aspx
VBScript Language Reference
http://msdn.microsoft.com/en-us/library/d1wf56tt(v=VS.85).aspx
WinHttpRequest object (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/aa384106(v=vs.85).aspx
Stream Object Properties, Methods, and Events
http://msdn.microsoft.com/en-us/library/windows/desktop/ms677486(v=vs.85).aspx

No comments :

Post a Comment