適材適所

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

MENU

WinHTTPとVBAでウェブから画像をダウンロードする

この記事では

WinHTTPで画像をダウンロードするためには

VBAで画像をダウンロードするためには、HTMLの簡単な解析が必要になります。

HTMLって何?という人はこちらの記事をご参照頂ければ幸いです。↓

VBAでウェブスクレイピング_IE操作編_その2 - 適材適所

通常、ウェブページにある画像は、HTMLと同じくウェブサーバー上に置いてあります。

そして、HTMLと同じように画像のパスをURLとして指定してWinHTTPでリクエストすると、その画像を取得することができます。

(ウェブサーバーの設定によっては、画像だけのリクエストを許可していない場合もあるのでその場合はあきらめましょう)

まず、一般的にウェブページ上の画像をダウンロードする場合は、その画像が載っているウェブページにアクセスします。

次にそのウェブページのHTMLから画像のパスを特定します。

そしてその画像パスに対してWinHTTPの要求処理を実行し、

ウェブサーバーから返されたデータをローカルに保存します。

一般的にHTML内のimgタグのsrc属性が画像のファイル名になります。

例えば、このブログの私のプロフィール画像は

 
<img src="https://cdn.profile-image.st-hatena.com/users/shinmai_papa/profile.png?1567396351" alt="id:shinmai_papa" class="profile-icon">

となっています。

試しに上記のHTMLの中の https://cdn.profile-image.st-hatena.com/users/shinmai_papa/profile.png をクリックしてみると、ブラウザに画像が表示されたかと思います。

WinHTTPでも考え方は同じです。

WinHTTPで画像ダウンロードするためには、

HTMLの中から対象の画像のsrc属性を見つけて、

ウェブサーバーにリクエストを送ってあげます。

WinHTTPで画像をダウンロードするコード

コード

実行する際は、変数の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://〇〇〇"
   req.Open "GET", url

   req.Send

   If req.Status <> 200 Then
      MsgBox "ステータスエラー"
      Exit Sub
   End If

   Dim urls As Collection: Set urls = New Collection
   Set urls = getUrls(req.ResponseText)

   Dim i As Long
   Dim extension As String
   For i = 1 To urls.Count
      Set req = New WinHttp.WinHttpRequest
      On Error Resume Next
      req.Open "GET", urls(i)
      req.Send
      extension = getExtension(urls(i))
      writeBinary req.ResponseBody, "C:\sample\" & i & "." & extension
      On Error GoTo 0
   Next i
End Sub

Function getUrls(body As String) As Collection
   Dim html As Object: Set html = New HTMLDocument
   html.Write body
   Dim returnColl As Collection: Set returnColl = New Collection
   Dim image As HTMLImg
   For Each image In html.getElementsByTagName("img")
      returnColl.Add image.src
   Next image
   Set getUrls = returnColl
End Function

Sub writeBinary(ByVal varByte As Variant, fPath As String)
   Dim byteLen As Long: byteLen = LenB(varByte)
   Dim buf() As Byte: ReDim buf(byteLen)
   buf = varByte
   Dim freeNum As Long: freeNum = FreeFile
   Open fPath For Output As #freeNum
   Close freeNum
   Open fPath For Binary Access Write As #freeNum
      Put #freeNum, 1, buf
   Close freeNum
End Sub

Function getExtension(url As String) As String
   Dim posi As Long: posi = InStrRev(url, ".")
   getExtension = Mid(url, posi + 1)
End Function

コードの解説

基本的な考え方は、「要求をオープンして送る」です。

7行目で、要求した結果のHTMLから、

getUrls関数というヘルパー関数によって

imgタグのsrc属性をコレクションとして得ています。

19行目のループで、各src属性のURLにWinHTTPを使って要求を送っています。

writeBinaryというヘルパー関数は少しわかりづらいですが、

レスポンスの中身をファイルに保存する処理です。

writeBinaryの中では、WinHttpRequest# ResponseBodyが、

応答本文をバイト配列で読み取りできることから、

それをバイト配列に格納してファイルに書き込んでいます。

VBAではあまり扱う機会がないかもしれないバイト列を扱うアイディアです。

getExtension関数は拡張子を得るための関数です。

これまたあまり使う機会のないかも知れない、InStrRev関数を使っています。

これは、第2引数の文字列を右から探索して、

第3引数の文字列が最初に現れる位置を返す関数です

(第1引数は省略されています)。

WinHTTP以外のところが少しややこしい・・・

おわりに

WinHTTPを使った画像をダウンロードする方法について解説してみました。

これを応用すれば、VBAを使ってウェブ上の画像を収集するプログラムが作れますね。

しかし、ウェブ上の画像は著作権で保護されているものもたくさんありますので、

ダウンロードする際は、くれぐれも許された範囲内でのご利用をお願いします。

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

参考サイト

WinHttpRequest オブジェクト - Win32 apps | Microsoft Docs 【VBA】Openステートメントでバイナリファイルを読み書きする | やさしいプログラミング備忘録