適材適所

PowerShellを中心にプログラミングやシステム管理の備忘録的なブログ

WinHTTPとVBAでウェブサイトのリンク一覧を取得する

WinHTTPでスクレイピングしてリンクのURL一覧を作ってみる

スクレイピングの目的は色々ありますが、こんなことができるよ的なサンプルの紹介です。

この記事では「WinHTTPを使って対象のページ上のリンク一覧をワークシートに書き出す」というサンプルを紹介します。

ウェブサイトのリンク一覧を作成するコード

次のコードは、変数urlで指定されたウェブページ上のリンクの文字列とリンク先URLをアクティブなシートに出力するものです。

もちろんVBAとWinHTTPによる実装です。

参照設定を行う前提で書いてありますので、実際にこのコードを実行するときは、下記の参照設定についてチェックをつけておく必要があります。

  • Microsoft WinHTTP Services, version○
  • Microsoft HTML Object Library
 
Sub WinHTTP_Sample()
   Dim req As WinHttp.WinHttpRequest: Set req = New WinHttp.WinHttpRequest
   Dim url As String:url = "https://www.yahoo.co.jp/"
   req.Open "GET", url
   req.Send

   If req.Status <> 200 Then
      MsgBox "レスポンスエラー"
      Exit Sub
   End If

   Dim html As Object: Set html = New HTMLDocument
   html.Write req.ResponseText
   Dim wrtRow As Long: wrtRow = 1
   Dim a As HTMLAnchorElement
   For Each a In html.getElementsByTagName("a")
      Cells(wrtRow, 1).Value = a.innerText
      Cells(wrtRow, 2).Value = a.href
      wrtRow = wrtRow + 1
   Next a

End Sub

コードの解説

2行目の

 
   Dim req As WinHttp.WinHttpRequest: Set req = New WinHttp.WinHttpRequest

は「req」という変数名でWinHttpRequestのオブジェクトを準備しています。

reqというのはRequestの頭から取りました。

参照設定を行っているので、WinHttpRequestのデータ型をそのまま指定しています。

4行目

 
   req.Open "GET", url

urlへのHTTP接続のための準備をしています。

Openメソッドの引数は次の3つです。

  1. HTTPの動詞。主にGET や POST など 1.接続先のURL。
  2. 「同期」or「非同期」の指定

同期と非同期の違いは、次の「Send」メソッド実行後の挙動にあります。

同期にすると、Sendメソッド実行後にサーバからの応答を全部受信してから、それ以降のコードが実行されるようになります。

つまり制御が戻ってきた時点で通信は完了しており、通信の状態をコード側で管理する必要がないため便利ですが、サーバーから受信するデータが大きい場合は、処理の待ち時間がその分増えます。

非同期の場合は、Sendメソッド後にサーバーからの応答を待たずに、すぐに後続の処理を行います。

そのため、後続の処理でサーバーからの応答を対象にしたいときはサーバーから応答が返ってきているか、後続の処理の中で逐一確認する必要があります。

後続の処理の中で応答を処理しない場合や、どうしてもサーバーからの応答に時間がかかるなどの通信に時間がかかってしまって仕方がないなどの特段の理由がなければ同期モードを選択しましょう。

Falseが同期、Trueが非同期です。省略値はFalseの同期です。

5行目

 
   req.Send

サーバに向けてリクエストを送信します。

HTTP通信で送信するBodyが引数になります。

主にPOSTメソッドでパスワード等を送信するときはBodyに指定することができます。

7~10行目

 
   If req.Status <> 200 Then
      MsgBox "レスポンスエラー"
      Exit Sub
    End If

レスポンスコードを調べます。

レスポンスコードは正常の場合200が返ってきます。

200以外は普通ではないレスポンスコードなので200以外の場合は処理を終了します。

12~13行目からはサーバーからの応答を処理します。

 
   Dim html As Object: Set html = New HTMLDocument
   html.Write req.ResponseText

HttpRequest#ResponseTextプロパティに、サーバーから返ってきた生のHTMLが入っています。

今回は、これをHTMLDocumentにパースしています。

HTMLDocumentを生成すると、レスポンスをDOMとして処理できるため、コードがすっきりして保守性が高まります。

しかしHTMLDocumentの生成はオーバーヘッドが大きいので大きなHTMLの場合処理が遅くなる場合があります。

処理に時間がかかるときはHTMLを正規表現で抽出するなどの対応も必要かもしれません。

求められる処理速度や処理の複雑さを勘案し、どちらを選択するかは状況によります。

16~21行目

 
   For Each a In html.getElementsByTagName("a")
      Cells(wrtRow, 1).Value = a.innerText
      Cells(wrtRow, 2).Value = a.href
      wrtRow = wrtRow + 1
   Next a

パースされたHTMLDocumentを使ってaタグのテキストとaタグのhref(リンク先)をシートに出力してます。

getElementsByTagNameの詳しい使い方は下記記事で言及しています。

www.tekizai.net

終わりに

VBAとWinHTTPでウェブサイトのリンクの一覧を取得するサンプルについて解説してみました。

WinHTTPを使うちょっとしたサンプルでしたが、WinHTTPを使えば、ブラウザに依存せずにVBAでスクレイピングすることができます。

要求をオープンして送る。

返ってきたものを処理する。

これがWinHTTPでスクレイピングする際の基本形になります。

この基本さえ押さえてしまえば、あとはウェブページの動きを分析して処理を組み立てることができます。

他にもスクレイピングに関する記事を書いておりますので、ぜひご参照頂ければ幸いです。

スクレイピング カテゴリーの記事一覧 - 適材適所

というわけで、ここまでお読みいただき、ありがとうございました。

参考サイト

IWinHttpRequest::Open method - Win32 apps | Microsoft Docs
VBAでのHTMLDocument VBAでHTMLの解析をしたいと思っています。 … - 人力検索はてな