適材適所

システム屋のくらげが気ままに書いているブログです。PowerShellやVBAなどプログラミング系の話をメインに書いています。

MENU

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

この記事では

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

その3ではWinHTTPを使うためのHTTPの説明をしました。 今回からWinHTTPの実践的な使い方に入っていきたいと思います。

スクレイピングの目的は色々ありますが、いくつかこんなことができるよ的なサンプルを作っていきたいと思います。

その第一段として「WinHTTPを使って対象のページ上のリンク一覧をワークシートに書き出す」というものを作ってみようと思います(そんな需要はあるかわかりませんが・・・)。

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

次のコードを実行すると、「url」変数に指定されたウェブページにあるリンクの文字列とリンク先URLをアクティブなシートに出力します。

コードの実行前に参照設定を行う必要があります。

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接続のための準備をしており、引数は3つです。

1つ目は、HTTPの動詞です。GET や POSTがメインとなることでしょうか。

2つ目は、URLを指定します。

3つ目は、開き方の指定です。「同期」or「非同期」のどちらかです。

同期モードは、次の「Send」メソッド実行時にサーバからの応答を全部受信しない制御が戻ってきません。

つまり制御が戻ってきた時点で通信は完了しており、通信の状態をコード側で管理する必要がないためとっても便利。

基本的には同期モードを使うことが多いような気がします。

通信に時間がかかるので通信中に別の処理を行いたい等、特段の理由がなければ同期モードを選択しましょう。

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

5行目

 
   req.Send

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

引数は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を生成すると、コードがすっきりして保守性が高まります。

しかし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

おわりに

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

このようにWinHTTPを使うことで、ブラウザに依存せずにスクレイピングをすることができます。

要求をオープンして送る。返ってきたものを処理する。これがWinHTTPでスクレイピングする際の基本形になります。

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

同じスクレイピングですが、IEを使ったスクレイピングとは違い、要求される知識、書き方は全く異なっていることがおわかり頂けたのではないでしょうか。

こちらの記事でもWinHTTPを使ったサンプルを紹介しています。

www.tekizai.net

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

参考サイト

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