【エクセル VBA】WinHTTP・XMLHTTP60を使ったスクレイピング ~SeleniumBasic・IEとの速度比較~

【エクセル-VBA】WinHTTP・XMLHTTP60を使ったスクレイピング ~SeleniumBasic・IEとの速度比較~ VBA

みなさんこんにちは、ZeroTerasu(@ZeroTerasu)です。

今回は、VBAのライブラリである「WinHTTP」および「XMLHTTP60」を用いたスクレイピング手法について解説していきます。VBAを用いたスクレイピング手法では、「Selenium Basic」または「IE」を用いたスクレイピングがポピュラーと思いますが、ブラウザを使用しない分高速処理が期待できるのではと思い、今回試してみました。

スクレイピングするサイト

今回は、私のブログサイトのトップページの中の全ての「<a>タグの”テキスト”」と 「<a>タグの”リンク先”」の情報を取得して、エクセルシートに書き込むというスクレイピングを実行しました。

取得する情報
取得情報元

ZeroTerasu Blog
https://zeroterasu.com/blog/

取得情報例

<a href=”https://zeroterasu.com/blog/” class=”site-name site-name-text-link” itemprop=”url”>
    <span class=”site-name-text” itemprop=”name about”>ZeroTerasu Blog</span>
</a>

取得する情報1 <a>タグのインナーテキスト
(上記の例では、「ZeroTerasu Blog」)
取得する情報2 <a>タグのインナー”href”属性値
(上記の例では、「https://zeroterasu.com/blog/」)
取得場情報数 本記事作成時点では、<a>タグ「119」個分

結果比較

操作方法WinHTTPXMLHTTP60SeleniumBasicIE
実行時間(秒)3.4722223063.4722223066.9444438856.944444613

・「WinHTTP」と「XMLHTTP60」はChrome・IEの約2倍速い

・「WinHTTP」と「XMLHTTP60」は同じ速度

・SeleniumBasic(Chrome)とIEはほぼ同じ速度

・SeleniumBasic(Chrome)とIE は毎回実行速度に大きくバラツキがある。

上記4番目の補足になりますが、ChromeとIEそれぞれ何回か実行してみましたが、実行する度に動作速度が変わりました。そのため、実行環境によっては、どちらの方が早いかの優劣が変わってくるものと思われます。

(サーバー側の処理速度に起因していると考えています。サーバーにアクセスが集中しているなど、速度が著しく遅い場合は、時間を空けてトライすべきかと考えます。※スクレイピング自体、サーバーに大きな負荷を掛ける処理になりますので、実行時にはサーバー負荷に十分ご配慮下さい。)

以下では、それぞれのメリット・デメリットおよびコード解説に進みます。

WinHTTP・XMLHTTP60のメリット・デメリット

WinHTTP・XMLHTTP60のメリット・デメリットをChrome・IEと比較してまとめました。

メリット デメリット
WinHTTP・XMLHTTP60 高速処理 JavaScript等から生成されるコンテンツの読み込みが不可。
SeleniumBasic(Chrome)・IE JavaScript等から生成されるコンテンツの読み込みが可能。

ブラウザを使用するため、処理が遅い。

取得対象の情報が、JavaScript等によって動的に生成される情報であれば、WinHTTP・XMLHTTP60は使用できません。

しかし、動的生成コンテンツ以外の情報であれば、ブラウザを使用するスクレイピング方法に比べて2倍以上のスピードが期待できそうです。

参照設定

下記のライブラリを参照設定に追加します。

追加方法は、「VBE」→「ツール(T)」→「参照設定(R)」から下記の名称を探してチェックマークにチェックを入れてください。

Microsoft WinHTTP Services, version 5.1(WinHTTP)

Microsoft XML, v6.0(XMLHTTP60)

Miocrosoft HTML Object Library(どちらの場合も使用します。)

【エクセル-VBA】WinHTTPを使ったスクレイピング1-1

コード

下記に今回使用したコードを掲載します。

「WinHTTP」と「XMLHTTP60」は、いずれもリクエスト結果をhtmlに書き込んだ後に、1秒間待機させています。(そのほかの待機方法も試してみましたが、この方法以外に成功例がありませんでした。)

ブラウザ(ChromeおよびIE)を使用した場合との結果比較のために、ブラウザを使用した場合のコードも掲載いたします。

WinHTTP
Sub WinHTTP_Sample()
    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim ws As Worksheet: Set ws = wb.ActiveSheet
    Dim begTime As Variant: begTime = Now()
    ws.Cells(1, 2) = Format(begTime, "yyyy/mm/dd hh:mm:ss")
    Dim req As WinHttp.WinHttpRequest: Set req = New WinHttp.WinHttpRequest
    Dim url As String: url = "https://zeroterasu.com/blog/"
    req.Open "GET", url
    req.Send
    
    Dim html As IHTMLDocument: Set html = New HTMLDocument
    html.write req.ResponseText

    Application.Wait(Now() + TimeValue("00:00:01"))
    Dim inputRow As Long: inputRow = 2
    Dim a As HTMLAnchorElement
    For Each a In html.getElementsByTagName("a")
        If IsNull(a.innerText) Then
            Debug.Print inputRow - 1 & " 番目の<a>タグのテキストが見つかりませんでした。"
            GoTo continue
        End If
        ws.Cells(inputRow, 1).Value = a.innerText
continue:
        If IsNull(a.href) Then
            Debug.Print inputRow - 1 & " 番目の<a>リンク先が見つかりませんでした。"
            GoTo continue2
        End If
        ws.Cells(inputRow, 2).Value = a.href
continue2:
        inputRow = inputRow + 1
        Debug.Print inputRow
    Next a
    ws.Cells(1, 4) = Format(Now(), "yyyy/mm/dd hh:mm:ss")
End Sub
XMLHTTP60
Sub XML_Sample()
    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim ws As Worksheet: Set ws = wb.ActiveSheet
    Dim begTime As Variant: begTime = Now()
    ws.Cells(1, 2) = Format(begTime, "yyyy/mm/dd hh:mm:ss")
    Dim req As XMLHTTP60: Set req = New XMLHTTP60
    Dim url As String: url = "https://zeroterasu.com/blog/"
    req.Open "GET", url
    req.Send
    
    Dim html As IHTMLDocument: Set html = New HTMLDocument
    html.write req.ResponseText
    
    Application.Wait(Now() + TimeValue("00:00:01"))
    Dim inputRow As Long: inputRow = 2
    Dim a As HTMLAnchorElement
    For Each a In html.getElementsByTagName("a")
        If IsNull(a.innerText) Then
            Debug.Print inputRow - 1 & " 番目の<a>タグのテキストが見つかりませんでした。"
            GoTo continue
        End If
        ws.Cells(inputRow, 1).Value = a.innerText
continue:
        If IsNull(a.href) Then
            Debug.Print inputRow - 1 & " 番目の<a>リンク先が見つかりませんでした。"
            GoTo continue2
        End If
        ws.Cells(inputRow, 2).Value = a.href
continue2:
        inputRow = inputRow + 1
        Debug.Print inputRow
    Next a
    ws.Cells(1, 4) = Format(Now(), "yyyy/mm/dd hh:mm:ss")
End Sub
(参考)SeleniumBasic
Sub SeleniumBasic_Sample()
    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim ws As Worksheet: Set ws = wb.ActiveSheet
    Dim begTime As Variant: begTime = Now()
    ws.Cells(1, 2) = Format(begTime, "yyyy/mm/dd hh:mm:ss")
    Dim dr As WebDriver: Set dr = New WebDriver
    dr.AddArgument "--headless"
    dr.Start "Chrome"
    Dim url As String: url = "https://zeroterasu.com/blog/"
    dr.Get url
    
    Application.Wait Now() + TimeValue("00:00:01")
    Dim inputRow As Long: inputRow = 2
    For Each a In dr.FindElementsByTag("a")
        ws.Cells(inputRow, 1).Value = a.Text
        ws.Cells(inputRow, 2).Value = a.Attribute("href")
        inputRow = inputRow + 1
        Debug.Print inputRow
    Next a
    ws.Cells(1, 4) = Format(Now(), "yyyy/mm/dd hh:mm:ss")
End Sub
(参考)IE
Sub IE_Sample()
    Dim wb As Workbook: Set wb = ThisWorkbook
    Dim ws As Worksheet: Set ws = wb.ActiveSheet
    Dim begTime As Variant: begTime = Now()
    ws.Cells(1, 2) = Format(begTime, "yyyy/mm/dd hh:mm:ss")
    Dim ie As InternetExplorer: Set ie = New InternetExplorer
    Dim url As String: url = "https://zeroterasu.com/blog/"
    ie.navigate url
    
    Do While ie.Busy = True Or ie.readyState < 4
        DoEvents
    Loop
    Dim htmlDoc As HTMLDocument
    Set htmlDoc = ie.document
    Dim inputRow As Long: inputRow = 2
    For Each a In htmlDoc.getElementsByTagName("a")
        ws.Cells(inputRow, 1).Value = a.Text
        ws.Cells(inputRow, 2).Value = a.getAttribute("href")
        inputRow = inputRow + 1
        Debug.Print inputRow
    Next a
    ws.Cells(1, 4) = Format(Now(), "yyyy/mm/dd hh:mm:ss")
End Sub

(おまけ)Microsoftドキュメント情報

今回使用した「WinHTTP」「XMLHTTP60」がそれぞれどのようなオブジェクトなのか気になったので、Microsoftドキュメントを確認してみました。

まずは、今回使用した2点のライブラリそれぞれのファイルを確認しました。(下記画像を参照下さい。)

Microsoft WinHTTP Services, version 5.1 参照設定
Microsoft XML, v6.0 参照設定
WinHTTP参照先ファイル=「winhttpcom.dll」
XMLHTTP60参照先ファイル=「msxml6.dll」

このファイル名を手掛かりにして、Microsoftドキュメントを確認しました。

いずれのファイルも「dll(Dynamic Link Library)」ファイルです。

dllファイルは、ライブラリやモジュールのWindowsでの名称と考えて頂ければ理解しやすいかと思います(dll=Dinamic Link “Library”ですので普通に”ライブラリ”ですね。)。

ライブラリは、プログラムから呼び出されたときに実行される部品です。

DLL は、複数のプログラムで同時に使用できるコードとデータを含むライブラリです。

実際、WinHTTPはエクセル以外にもOutlook等でも使用されています。

Microsoft Windows HTTP Services (WinHTTP)ドキュメント:

クリックするとリンク先が別タブで開きます。

ドキュメントによると、「WinHTTPは、HTTPプロトコルを通じてHTTPサーバーにリクエストを送信するためのHTTPクライアントAPI」のようです。

IXMLHTTPRequestドキュメント:

クリックするとリンク先が別タブで開きます。

「 msxml6.dll 」ファイルの中に、「 XMLHTTP 」オブジェクトが実装されており、このオブジェクトを利用してHTTPリクエスト送信・レスポンス解析を実行しているといった内容が説明されています。

コメント

タイトルとURLをコピーしました