はじめに
下記サイトの方で「ヘッドレスモードでファイルをダウンロードができない」旨の質問を頂きました。
質問の回答になるサンプルを提示したところ、無事解決したようです。
私もヘッドレスモードでファイルをダウンロードできないことは初めて知る内容でしたし、いいネタなので記事化することにしました。
何故できないのか
ヘッドレスモードでなければアンカータグをクリックするだけでファイルをダウンロードすることが出来ますが、ヘッドレスモードになると何も反応しなくなります。
正確には、プログラムは正常終了しますが保存先パスにファイルが存在しない状態になります。
こちらで議論されていますが、セキュリティの観点からのようです。
https://bugs.chromium.org/p/chromium/issues/detail?id=696481
回避方法
Pythonによる回避方法のサイトを見つけたのですが、これをTinySeleniumVBAでどう実現するのか難しそうでした。
もう少し調べるとSeleniumBasic(SeleniumVBA)での回避方法を見つけました。
Python版に比べるとダウンロード先を指定するだけで非常にシンプルです。シンプルすぎて本当に出来るのか逆に不安でした。
Dim bot As New ChromeDriver, post As Object
With bot
.SetPreference "download.default_directory", ThisWorkbook.Path & "\"
.Timeouts.ImplicitWait = 1000
.AddArgument "--headless"
.Start
.get "http://"
end with
手始めにTinySeleniumVBAに書き換えて試してみたところ、ヘッドレスモードでダウンロードすることができました。
ソースコード
TinySeleniumVBAは最新版v0.1.3のEdge上で確認しています。
CSVファイルがあるサイトとして下記をサンプルとして採用しました。
ヘッドレスモードでCSVファイルを、ThisWorkbook.pathフォルダの配下にダウンロードできました。
※ThisWorkbook.pathフォルダは任意に変更してください。
Dim Driver As New WebDriver
Driver.Edge "C:\Tools\edgedriver_win64\msedgedriver.exe"
Dim cap As Capabilities
Set cap = Driver.CreateCapabilities()
cap.AddArgument "--headless"
cap.AddPref "download.default_directory", ThisWorkbook.path & "\"
Driver.OpenBrowser cap
' Navigate to e-stat.go.jp
Dim baseUrl As String
baseUrl = "https://www.e-stat.go.jp"
Driver.Navigate baseUrl & "/stat-search/files?page=1&layout=datalist&toukei=00200521&tstat=000001011777&cycle=0&tclass1=000001094741&tclass2val=0"
Dim csvanchors
csvanchors = Driver.FindElements(By.XPath, "//a[@data-file_type='CSV']")
csvanchors(0).Click
ThisWorkbook.pathフォルダではなく、ユーザーのダウンロードフォルダにする場合は下記に書き換えてください。
Dim path As String
Dim downloadPath As String
path = CreateObject("Wscript.Shell").SpecialFolders("MyDocuments")
downloadPath = Left(path, InStrRev(path, "\")) & "DownLoads"
cap.AddPref "download.default_directory", downloadPath & "\"
【2022/05/22追記】
Mac版TinySeleniumVBAのテストをしていて、下記2点を修正する必要がありました。
cap.AddPref "download.default_directory", ThisWorkbook.path & "\"
↓
cap.AddPref "download.default_directory", ThisWorkbook.path
末尾の& "\\"
が不要でした。これがあると"DownLoad\"というフォルダが作成されてしまいます。
Windowsはパス区切りが複数回続けて書いても問題ないですがMacは駄目です。
csvanchors = Driver.FindElements(By.XPath, "//a[@data-file_type='CSV']")
↓
csvanchors = Driver.FindElements(By.XPath, "//a[@data-file_type=""CSV""]")
CSVのところは、ダブルクォーテーションにしないと正しい結果が得られませんでした。
最後に
シンプルになったのはバージョンが上がったからかも知れませんね。
他の言語でも同様にシンプルに回避できるようになっているかは確認していません。