インターネットからファイルやデータのダウンロードを行うには
VBAを使ってインターネットのデータをダウンロードする方法にはいくつかあります。
ここで紹介するWin32APIを使う方法や、WshShellやShell関数で他アプリケーションを呼び出す方法や、InternetExplorerの仕組みを利用する方法や、XMLHTTPRequestを利用したりなど様々です。
それぞれ一長一短がありますが、一般的にブラウザで行う「右クリック+名前を付けて保存」でのファイルダウンロードと同じ動作をVBAで一番簡単に実現できるWin32APIでの方法を紹介します。
なお、高速にダウンロードしたい場合や、よりカスタマイズしたい場合などはVBAではなくC#やPythonやPHPなどを利用した方がよいと思われますので、そちらを探してみてください。
実際私自身もネットから必要なデータを落とすプログラムを作っていますが、圧倒的にコーディングがラクなのと結果的に高速に動作することからC#のSystem.Netクラスで実装することが多いです。
サーバ負荷を増大させるような連続アクセスは控える
インターネットからファイルをダウンロードする際に注意すべき点があります。
それは、サーバーに対して休み無く連続でアクセスすることを控える、という点です。
あまりに高頻度でのアクセスはそういう意図が無かったとしてもDDoS攻撃とみなされる恐れがあります。
以降のサンプルコードでは1ファイルしか処理をしませんが、拡張後に連続してダウンロードを行う場合を考慮して、Sleep関数で1秒休止するようにしています。
サイトによっては自動取得(スクレイピング)自体を禁止していることもあります。Yahooのファイナンス情報などはそのようです。
そのあたりを確認した上でファイルのダウンロードを行ってください。
Win32APIを使う
VBAでインターネットからファイルのダウンロードを行うにはWin32APIの3つの関数を使います。
URLDownloadToFile | 指定URLのファイルをダウンロードする |
DeleteUrlCacheEntry | 指定URLのキャッシュをクリアする |
Sleep | 指定ミリ秒だけ処理を止める |
これらのAPIは今ではVBAぐらいでしか利用されないかもしれません。それぐらい今では他の言語ではインターネット操作の仕組みが充実しています。
サンプルコード
Win32APIを利用して、PNGファイルをダウンロードするサンプルコードです。説明しやすいように3つに分けていますが、1つのモジュールに繋げて書いて利用できます。
実行すると、PNG画像ファイルをダウンロードします。ダウンロードするPNGファイルは当サイトのあるページで使っているエラーダイアログのPNG画像ファイルです。
動作させるには2つ目のコードのDownloadFileTest関数を実行します。
1. Win32APIの宣言
3つのWin32APIを標準モジュール等のコードの先頭あたりに書きます。DownloadFile関数より上に書いておく必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
'// 64bit版 #If VBA7 And Win64 Then '// 指定URLファイルのダウンロード Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long '// キャッシュクリア Private Declare Function DeleteUrlCacheEntry Lib "wininet" Alias "DeleteUrlCacheEntryA" (ByVal lpszUrlName As String) As Long '// スリープ Private Declare PtrSafe Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long) '// 32bit版 #Else '// 指定URLファイルのダウンロード Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long '// キャッシュクリア Private Declare Function DeleteUrlCacheEntry Lib "wininet" Alias "DeleteUrlCacheEntryA" (ByVal lpszUrlName As String) As Long '// スリープ Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) #End If |
2. 任意のURLを指定してDownloadFile関数を呼び出す関数
この関数が最初に動かす関数です。
URLと保存先パスを指定してDownloadFile関数を呼び出します。
ここでは保存先パスにファイル名まで指定していますが、これはURLDownloadToFile関数の第三引数の形式に合わせているためです。
フォルダパスだけにしたい場合であればファイル名部分をURLからもってくるなどの対応が必要になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
'// URLを指定してDownloadFile関数を呼び出す Sub DownloadFileTest() Dim sUrl As String '// ダウンロード対象ファイルのURL Dim sDir As String '// ダウンロードファイルを保存するローカルPCのフォルダパス '// URL設定 sUrl = "https://aaa.com/a.png" sDir = "C:\web\ダウンロード\a.png" '// ダウンロード Call DownloadFile(sUrl, sDir) '// 1秒スリープ Call Sleep(1000) End Sub |
引数のURLのファイルをダウンロードする関数
URLのファイルをダウンロードする関数です。本体ともいえる関数です。
5行目で指定URLのキャッシュをクリアし、古いファイルのダウンロードを防ぎます。
ここでは戻り値を取得していませんが、もし戻り値の判定を行う場合はキャッシュが無い場合はキャッシュのクリアが出来ないため、DeleteUrlCacheEntry関数の戻り値はFALSE(失敗)になることの考慮が必要です。
8行目で指定URLのファイルをダウンロードします。ダウンロードに失敗した場合はイミディエイトウィンドウにそのURLを出力します。
URLDownloadToFile関数の使い方ですが、1番目の引数は0固定、2番目がURL、3番目が保存先パス、4番目と5番目も0固定です。URLと保存先パスを指定しているだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
'// 指定URLファイルのダウンロードを行う Sub DownloadFile(a_sUrl As String, a_sDir As String) Dim ret '// 戻り値 '// キャッシュクリア Call DeleteUrlCacheEntry(a_sUrl) '// ダウンロード ret = URLDownloadToFile(0, a_sUrl, a_sDir, 0, 0) '// ダウンロード失敗時 If ret <> 0 Then Debug.Print a_sUrl & ":ダウンロード失敗" End If End Sub |