Excel VBAでWebページを取得する第三の方法

The third way to get web page from the web by Excel VBA


 

第一の方法とは

次のソースコードを見てください。

#If VBA7 Then
    Private Declare PtrSafe Function GetInputState Lib "user32" () As LongPtr
#Else
    Private Declare Function GetInputState Lib "user32" () As Long
#End If

#If VBA7 Then
  Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
  Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Private Function F_GetHTMLDoc(ByVal IE As InternetExplorer, _
                              ByVal URL As String, _
                              ByVal mySecond As Long, Optional _
                              ByVal Flag As Boolean = False) _
                              As HTMLDocument
  IE.Navigate URL

  IE.Visible = Flag

  Dim myTime As Date: myTime = Now + TimeSerial(0, 0, mySecond)

  Do While IE.Busy = True Or IE.ReadyState <> READYSTATE_COMPLETE
    If GetInputState() = True Then DoEvents

    Sleep 1

    If Now > myTime Then
      IE.Refresh
      myTime = Now + TimeSerial(0, 0, mySecond)
    End If
  Loop

  myTime = Now + TimeSerial(0, 0, mySecond)

  Do While IE.Document.ReadyState <> "complete"
    If GetInputState() = True Then DoEvents

    Sleep 1

    If Now > myTime Then
      IE.Refresh
      myTime = Now + TimeSerial(0, 0, mySecond)
    End If
  Loop

  Set F_GetHTMLDoc = IE.Document
End Function

第一の方法は、「Microsoft Internet Controls」と「Microsoft HTML Object Library」を参照して、InternetExplorerオブジェクトを利用して、NavigateメソッドでURLを読み込み、DocumentプロパティでHTMLDocumentオブジェクトを取得します。

InternetExplorerオブジェクトとHTMLDocumentオブジェクトの両方を使うので、確実ですが、遅い方法です。

 

第二の方法とは

#If VBA7 Then
    Private Declare PtrSafe Function GetInputState Lib "user32" () As LongPtr
#Else
    Private Declare Function GetInputState Lib "user32" () As Long
#End If

#If VBA7 Then
  Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
  Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Private Function F_GetHTMLDoc2(ByVal URL As String) As HTMLDocument
    Dim HTML As MSHTML.HTMLDocument
    Set HTML = New MSHTML.HTMLDocument
    
    Dim myDocument As MSHTML.HTMLDocument
    Set myDocument = HTML.createDocumentFromUrl(URL, vbNullString)
    
    Do While HTML.ReadyState <> "complete"
        If GetInputState() = True Then DoEvents
        Sleep 1
    Loop
    
    Set F_GetHTMLDoc2 = myDocument
    
    Set HTML = Nothing
    Set myDocument = Nothing
End Function

第二の方法は、「Microsoft HTML Object Library」のみを参照して、InternetExplorerオブジェクトは利用せずに、直接HTMLDocumentオブジェクトを取得します。

InternetExplorerオブジェクトを使わないので、第一の方法よりは速い方法です。

まずは親となるHTMLDocumentオブジェクトを変数「HTML」で用意します。

「createDocumentFromUrl」メソッドでURLにアクセスし、HTMLDocumentオブジェクト取得し、変数「myDocument」に格納します。

 

第三の方法とは

Private Function F_GetHTMLDoc3(ByVal URL As String) As HTMLDocument
    Dim HTTP As Object
    Set HTTP = CreateObject("MSXML2.XMLHTTP")
    
    HTTP.Open "GET", URL, False
    HTTP.send (Null)
    
    Dim myHTMLDocument As IHTMLDocument
    Set myHTMLDocument = New IHTMLDocument
    
    myHTMLDocument.Write HTTP.responseText
    
    Set F_GetHTMLDoc3 = myHTMLDocument
    
    Set myHTMLDocument = Nothing
    Set HTTP = Nothing
End Function

第三の方法は、「Microsoft XML. v3.0」、「Microsoft HTML Object Library」を参照します。参照結果は、変数「F_GetHTMLDoc3」にHTMLDocumentオブジェクトとして格納されます。

この方法では、スピードは最速なのですが、第一・第二の方法と違い、HTMLDocumentオブジェクトではなく、文字列型データを戻り値とすることに注意が必要です。

つまり、「HTTP.responseText」の戻り値はHTMLDocumentオブジェクトではないので、取得データに対して「getElementsByClassName」メソッドなどのHTMLDocumentオブジェクトの機能(メソッド・プロパティ)が使えないのです。

ですから、自前でHTMLDocumentオブジェクトを作成します。

変数「myHTMLDocument」を用意して、「Write」メソッドで「HTTP.responseText」の文字列データを書き込みます。

一つ、注意点としては、変数「myHTMLDocument」のデータ型は、「HTMLDocument」型や、「IHTMLDocument2」型ではダメで、「IHTMLDocument」型である必要があります。

たしかに「Write」メソッドを規定しているのは「IHTMLDocument2」インターフェイスですが、実は、「IHTMLDocument」のインターフェイスには「IHTMLDocument interface」から「ihtmldocument8 interface」の8つがあります。したがって、「Write」メソッドを使うには、これらを代表して「IHTMLDocument」型を使う必要があるのではないか、と考えています。

ということで、第二の方法よりもスピードが速いときに限って、この方法を使うメリットがあります。

もう一つのメリットとしては、IEを使わないということです。今後、Edgeが企業でのデフォルト・ブラウザになるような状況が実現すれば、あるいは現状のようにGoogle Chromeが実質デフォルトである間は、この方法も一定の存在価値があるということです。

 

おわりに

考え方としては、まず第一の方法で作ってみる、スピードに満足できないときは第三の方法で試してみる、第三の方法で安定性に欠けるときは第二の方法を試してみる、という手順で考えるのがいいのではないしょうか。

コメントを残す