【備忘】VBAでネット上のファイルを自動でダウンロードする方法

おはこんばんにちは。 今日は備忘も備忘、VBAネタです。会社でVBAを使って、ファイルをダウンロードする方法について少し質問を受け、その回答に困ったので、ちょっとコードを書いてみたいと思います。

  • やりたいこと

VBAを用いてDOM構造の中から欲しいファイルをタグ名を用いてダウンロードしたい」がやりたいことです。正直、Rを使ったりやSeleniumを併用したりするとすぐ取れるのですが、VBAXpathにあまり対応してないらしく複雑なDOMには太刀打ちできない感じです。ご質問を受けた時は、この複雑なDOMから取得したい要素にどうやってたどり着けば良いのかとばかり考えていたのですが、ファイルをダウンロードするのが主たる目的ですのでそれならWindows APIを用いればそこまで難しくないかなと思いました。そのコードの実装を備忘として残しておきたいので、この記事を書いています。今回は実装の例として以前以下の記事で用いた財務省金利情報のページから国債金利csvファイルをダウンロードするコードを書いてみたいと思います。

osashimix.hatenablog.com

  • VBAによる実装

まず、VBAでWEBスクレイピングを行うためには2つのライブラリファイルを参照可能にする必要があります。1つ目は「Windows HTML Object Library」で2つ目は「Microsoft Internet Controls」です。これはVBE画面のツール(T)タブから設定ができます(以下の画像参照)。この2つにチェックをつけて、OKを押下します。

f:id:osashimix:20181027112709p:plain

これで設定は完了です。財務省金利情報のページはここです。このページの金利情報というリンクを押下すれば以下のようにファイルダウンロードの通知が現れます。

f:id:osashimix:20181027113534p:plain

今回はこのサイトのURLと要素を一意に絞るキーがわかっているとして、コードを書いていきます。今回の場合は以下の通り、jgbcm.csvがキーとなります。ファイルのダウンロードに関わる要素はリンク属性であるので、コードもキーを持つリンク属性のhrefを読み取り、それをURLDownloadToFile関数に渡すことでファイルをダウンロードする構成にします。

f:id:osashimix:20181027113901p:plain

では、コードを書いていきます。

' 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

f:id:osashimix:20181027124602p:plain

無事、ダウンロードすることができました。やってみると、たいしたことない話ですね。ただ、一意に要素を絞るKeyがないとやはりVBAではWEBスクレイピングは難しそうです。こういうあたり、どうもVBAが好きになれないところです。会社でもPythonやRが使えたらどれだけ作業効率が上がることか。まあとりあえず、当面はVBAでどうにかこうにかやるしかなさそうです。今週はできればもう一本投稿したいと思っているので、そちらもご笑覧ください。 では。