【備忘】VBAでネット上のファイルを自動でダウンロードする方法
おはこんばんにちは。 今日は備忘も備忘、VBAネタです。会社でVBAを使って、ファイルをダウンロードする方法について少し質問を受け、その回答に困ったので、ちょっとコードを書いてみたいと思います。
- やりたいこと
「VBAを用いてDOM構造の中から欲しいファイルをタグ名を用いてダウンロードしたい」がやりたいことです。正直、Rを使ったりやSeleniumを併用したりするとすぐ取れるのですが、VBAはXpathにあまり対応してないらしく複雑なDOMには太刀打ちできない感じです。ご質問を受けた時は、この複雑なDOMから取得したい要素にどうやってたどり着けば良いのかとばかり考えていたのですが、ファイルをダウンロードするのが主たる目的ですのでそれならWindows APIを用いればそこまで難しくないかなと思いました。そのコードの実装を備忘として残しておきたいので、この記事を書いています。今回は実装の例として以前以下の記事で用いた財務省の金利情報のページから国債金利のcsvファイルをダウンロードするコードを書いてみたいと思います。
- VBAによる実装
まず、VBAでWEBスクレイピングを行うためには2つのライブラリファイルを参照可能にする必要があります。1つ目は「Windows HTML Object Library」で2つ目は「Microsoft Internet Controls」です。これはVBE画面のツール(T)タブから設定ができます(以下の画像参照)。この2つにチェックをつけて、OKを押下します。
これで設定は完了です。財務省の金利情報のページはここです。このページの金利情報というリンクを押下すれば以下のようにファイルダウンロードの通知が現れます。
今回はこのサイトのURLと要素を一意に絞るキーがわかっているとして、コードを書いていきます。今回の場合は以下の通り、jgbcm.csvがキーとなります。ファイルのダウンロードに関わる要素はリンク属性であるので、コードもキーを持つリンク属性のhrefを読み取り、それをURLDownloadToFile関数に渡すことでファイルをダウンロードする構成にします。
では、コードを書いていきます。
' Winows APIのURLDownloadToFile関数を呼び込むためのおまじない 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 'ファイルダウンロードマクロを部品として作成 Sub fileDL(URL As String, _ Key As String, _ savepath As String) Dim objIE As InternetExplorer Dim fileName As String, link As String, saveName As String Dim result As Long Dim objLink As Object ' URLのホームページにアクセス Set objIE = CreateObject("InternetExplorer.Application") objIE.navigate URL ' ページの読み込み待ち Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE DoEvents Loop ' DOMのリンク属性の中からKeyを含む要素を特定し、そのリンクを取得(一意に定まるKeyでないと特定できた最初のファイルをDL) For Each objLink In objIE.document.Links If InStr(objLink.outerHTML, Key) > 0 Then link = objLink.href Exit For End If Next If link = "" Then MsgBox "特定できませんでした" Exit Sub End If ' ファイル名とファイルを保存先を作成 fileName = Mid(link, InStrRev(linkValue, "/") + 1) saveName = savepath & "\" & fileName ' ダウンロードを実行 result = URLDownloadToFile(0, link, saveName, 0, 0) ' 0の場合は成功、失敗の場合は-2146697210(resultをlongで定義する必要あり) If result <> 0 Then MsgBox "ダウンロードできませんでした" End If End Sub
この部品をメインのマクロに組み込み使用すると、
Sub test() Call fileDL("https://www.mof.go.jp/jgbs/reference/interest_rate/", _ "jgbcm.csv", _ "C:\Users\aashi\Downloads") End Sub
無事、ダウンロードすることができました。やってみると、たいしたことない話ですね。ただ、一意に要素を絞るKeyがないとやはりVBAではWEBスクレイピングは難しそうです。こういうあたり、どうもVBAが好きになれないところです。会社でもPythonやRが使えたらどれだけ作業効率が上がることか。まあとりあえず、当面はVBAでどうにかこうにかやるしかなさそうです。今週はできればもう一本投稿したいと思っているので、そちらもご笑覧ください。 では。