t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Excel VBAでIEを操作するクラスを作成中

ExcelでのIE操作クラスを作成中。
といってもただのIEラッパーで、読み込み完了処理を隠蔽してVBA初心者にも使いやすくするのが主目的である。

私がVBAIE操作を始めた頃はインターネット上で調べるしかなくて、まずいサイトにあたるとコードが不安定だったりした。
当時はCreateObjectでIEを作っているサンプルが多くてメソッドを調べるのに凄く苦労した覚えがある。

主に参考にしていたサイトは三流君のページ
三流君VBAでIE操作 InternetExplorer.Applicationを操作する

2013年の終わり頃にVBAIE操作する書籍が出たので飛びついた。

IEを自在に操るExcelVBAプログラミング入門

IEを自在に操るExcelVBAプログラミング入門

もう一種類は同年4月頃に出てたらしいが、私が書店で見かけた頃には2つともそろっていた。

Excel VBAでIEを思いのままに操作できるプログラミング術 Excel 2013/2010/2007/2003対応

Excel VBAでIEを思いのままに操作できるプログラミング術 Excel 2013/2010/2007/2003対応

決め手になったのは、IEを自在に操る~の方にちょろっとF#連携があったこと。(結局作ったのはVB.Net連携なんだけれど、参考になった。)

一点残念だと思うのは、約300ページあるうちの100ページがVBAの基礎に当てられていること。ここは中・上級書籍として割り切って、さらに高度な話題を扱って欲しかったところである。しかし、VBAの中・上級書籍はだいたい絶版してしまうので、これで良かったのかもしれない。両書籍ともKindle化されており、当面は安泰と思われる。

という訳で今では別に珍しくもなんとも無いのだけれど、読み込み完了の判断が今ひとつで苦労している。

以下、IExplore.clsのコード。
参照設定にMicrosoftInternetControlsが必要。

Option Explicit

Private WithEvents IE As InternetExplorer
Private DocComp As Boolean

Public Sub Navigate(URL)
    DocComp = False
    IE.Navigate URL
    Do While IE.Busy Or IE.ReadyState < READYSTATE_COMPLETE
        DoEvents
    Loop
    
    Dim StartTime As Date
    StartTime = Now
    Do While IE.Busy Or Not DocComp
        DoEvents
        If (Now - StartTime) > 3 Then
            '3秒でタイムアウト処理、上でReadyStateチェックまでしているので、
            'なぜかDocumentCompleteのURLとアドレスバーが一致しなかった時の無限ループ回避用。
            '今のところ、テストでは発動していない。(コードが間違っているのかも。)
            Debug.Print "TimeOut"
            Exit Do
        End If
    Loop
End Sub

Private Sub Class_Initialize()
    Set IE = New InternetExplorer
    IE.Visible = True
End Sub

'以下のDebug.Printはイベントの発火順を見るためのコード。完成品からは取り除く予定。
Private Sub IE_DocumentComplete(ByVal pDisp As Object, URL As Variant)
    DocComp = (URL = IE.Document.URL)
    Debug.Print "DocumentComplete_Fired", URL
End Sub

Private Sub IE_DownloadComplete()
    Debug.Print "DownloadComplete_Fired"
End Sub

Private Sub IE_NavigateComplete2(ByVal pDisp As Object, URL As Variant)
    Debug.Print "NavigateComplete2_Fired", URL
End Sub

そして以下がIExploreクラスを利用した標準モジュールのサンプル

Sub test()
    Dim x As New IExplore
    Debug.Print "--Start--"
    x.Navigate "google.com"
    Debug.Print "Finished"
End Sub

これを3回試した結果が、以下である。

--Start--
DownloadComplete_Fired
NavigateComplete2_Fired     https://www.google.co.jp/?gfe_rd=cr&ei=4dDkVMH7AobS8gfe24CYCQ&gws_rd=ssl
DownloadComplete_Fired
DocumentComplete_Fired      https://www.google.co.jp/?gfe_rd=cr&ei=4dDkVMH7AobS8gfe24CYCQ&gws_rd=ssl
Finished
DownloadComplete_Fired
DownloadComplete_Fired
--Start--
DownloadComplete_Fired
NavigateComplete2_Fired     https://www.google.co.jp/?gfe_rd=cr&ei=5dDkVMqPOIzS8gfz1oCoBA&gws_rd=ssl
DownloadComplete_Fired
DocumentComplete_Fired      https://www.google.co.jp/?gfe_rd=cr&ei=5dDkVMqPOIzS8gfz1oCoBA&gws_rd=ssl
Finished
DownloadComplete_Fired
--Start--
DownloadComplete_Fired
NavigateComplete2_Fired     https://www.google.co.jp/?gfe_rd=cr&ei=69DkVIPKA4zS8gfz1oCoBA&gws_rd=ssl
DownloadComplete_Fired
DocumentComplete_Fired      https://www.google.co.jp/?gfe_rd=cr&ei=69DkVIPKA4zS8gfz1oCoBA&gws_rd=ssl
Finished

ご覧の通り、FInishedで終わっているのは最後の一回で、あとの2回はFinishedの後にDownloadCompleteイベントが発火されている。
この状態でも必要なタグは取ってこれるが、ちょっと気持ち悪い。Googleだからこれで済んでいるが、業務で使用している課題管理システムに使用してみたところもっと多くのDownloadCompleteがFinish後に発火されてしまう。

完了後にちょっとSleepしてみるというのも考えたが、適当に一定時間待つというコードはCPU100%の時やネットワーク混雑時に失敗する可能性があるのであまりスマートでは無い。

書籍:IEを自在に操る~の良いところは、特定タグを待つテクニックを紹介しているところ。それも万能の解ではないけれど、ひとまず特定サイトへの対処へは使えそうだ。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。