SeleniumBasicでダウンロード作業をする際に役立つコードの紹介です。
私は、SeleniumBasicで各ホームページにアップされているPDFデータやJPEGデータ等の画像データ(バイナリデータ)をダウンロードすることがよくあります。
SeleniumBasicでファイル容量が重いファイルを複数ダウンロードする場合、ダウンロードが完了する前にコードが終了してしまい、ファイルダウンロードが中断してしまう事があSります。また、複数ダウンロードを同時並行してしまうと、Webサーバの負荷が増えてしまいます。
そこで、今回紹介するコードは、1件毎にデータダウンロードが完了してから次のデータダウンロードに移るため、上記問題を解決する事ができます。
紹介したいコードが大きく分けて二つあり、2回に分けて説明します。
1回目は、HTTPリクエストを用いてダウンロードする方法を紹介します。
- 利用目的は業務効率化です。(テスト自動化ではありません)
- ブラウザはGoogleChromeが対象です。(EdgeやFirefoxは対象外)
- 原文のVBAでは現在エラー発生する場合が多いため、修正を加えてます。
Examples.xlsmの保存場所(ここをクリック)
Examples.xlsmが保存されている場所は、SeleniumBasicがインストールされているサブフォルダ内になります。SeleniumBasicのインストール完了時に保存フォルダを確認することができます。ただ、大体以下フォルダのどちらかにファイル保存されています。
- C:\Program Files\Seleniumbasic\Examples\Excel
- shell:Local AppData\SeleniumBasic\Examples\Excel
PDFをHTTPリクエストでデータダウンロード
まず、最初に紹介するコードは、ホームページ上のPDFデータリンクを取得する方法です。大まかなコードの構成は、以下のとおりです。
・PDFデータのリンクデータ要素をキャッチ
・Download_EleLink関数の呼出し(引数:リンク要素、保存フルパス)
・リンク要素を辞書型に登録(JavaScript)
・HTTPリクエスト(XMLHTTP.6.0)
・PDFファイルのバイナリデータを取得、作成(ADODB.Stream)
ダウンロード先は、京都府ホームページを利用させていただきました。実行データ全文は、以下のとおりです。
Option Explicit
Private Sub Usage_Download_EleLink()
Dim Driver As New ChromeDriver, ele As WebElement
Driver.Get "https://www.pref.kyoto.jp/kenkoshishin/pdfdown.html"
Set ele = Driver.FindElementByPartialLinkText("飲酒")
Download_EleLink ele, ThisWorkbook.Path & "\飲酒.pdf"
Driver.Quit
End Sub
Private Function Download_EleLink(ele As WebElement, save_as As String)
Dim info As Selenium.Dictionary
Set info = ele.ExecuteScript("return {" & _
"link: this.href," & _
"agent: navigator.userAgent," & _
"lang: navigator.userLanguage," & _
"cookie: document.cookie };")
On Error Resume Next
Static xhr As Object
If xhr Is Nothing Then Set xhr = CreateObject("Msxml2.ServerXMLHTTP.6.0")
xhr.Open "GET", info("link")
xhr.setRequestHeader "User-Agent", info("agent")
xhr.setRequestHeader "Accept-Language", info("lang")
xhr.setRequestHeader "Cookie", info("cookie")
xhr.Send
On Error GoTo 0
If (xhr.Status \ 100) - 2 Then Err.Raise 5, , xhr.Status & " " & xhr.StatusText
Static bin As Object
If bin Is Nothing Then Set bin = CreateObject("ADODB.Stream")
If Len(Dir$(save_as)) Then Kill save_as
bin.Open
bin.Type = 1
bin.Write xhr.ResponseBody
bin.Position = 0
bin.SaveToFile save_as
bin.Close
End Function
以下、各構文を分解して説明します。
Usage_Download_EleLink
京都府ホームページをゲットし、関数へ引き渡す準備のプロシージャになります。
Private Sub Usage_Download_EleLink()
Dim Driver As New ChromeDriver, ele As WebElement
Driver.Get "https://www.pref.kyoto.jp/kenkoshishin/pdfdown.html"
Set ele = Driver.FindElementByPartialLinkText("飲酒")
Download_EleLink ele, ThisWorkbook.Path & "\飲酒.pdf"
Driver.Quit
End Sub
4行目:PDFデータのリンクデータ要素をキャッチ
5行目:Download_EleLink関数の呼出し(引数:リンク要素、保存フルパス)
Download_EleLink
Usage_Download_EleLinkから呼び出された関数の説明になります。各カテゴリーに分けて説明していきます。
リンク要素を辞書型に登録(JavaScript)
HTTP Headerセットをするために、リンク要素から取得できるURLとHeader情報をJavaScriptを利用して、Selenium専用の辞書型に代入します。
Dim info As Selenium.Dictionary
Set info = ele.ExecuteScript("return {" & _
"link: this.href," & _
"agent: navigator.userAgent," & _
"lang: navigator.userLanguage," & _
"cookie: document.cookie };")
1行目:Selenium専用の辞書型の宣言
2~6行目:JavaScriptでinfoに辞書登録
HTTPリクエスト(XMLHTTP.6.0)
辞書型に登録したHeader情報を使用し、HTTPリクエストを実行します。
info("lang")が空白の場合があり、エラー6行目でエラーする場合がありますので、1行目のOn Error Resume nextで強制的にエラー回避させています。
On Error Resume Next
Static xhr As Object
If xhr Is Nothing Then Set xhr = CreateObject("Msxml2.ServerXMLHTTP.6.0")
xhr.Open "GET", info("link")
xhr.setRequestHeader "User-Agent", info("agent")
xhr.setRequestHeader "Accept-Language", info("lang")
xhr.setRequestHeader "Cookie", info("cookie")
xhr.Send
On Error GoTo 0
If (xhr.Status \ 100) - 2 Then Err.Raise 5, , xhr.Status & " " & xhr.StatusText
2行目:静的変数宣言(Static)することで、2回目のコード実行時にCreateOjbect生成を不要にしている。
4~8行目:HTTPリクエスト実行。Header情報は前段のinfoから登録。
10行目:HTTPステータスコードを調べて、200台以外はエラーを出力。HTTPステータスコードの一覧は以下参照ください。
Pdfファイルのバイナリデータを取得、作成(ADODB.Stream)
HTTPリクエスト後、"ADODB.Stream"でPDFのバイナリデータを取得し、データを保存します。
Static bin As Object
If bin Is Nothing Then Set bin = CreateObject("ADODB.Stream")
If Len(Dir$(save_as)) Then Kill save_as
bin.Open
bin.Type = 1
bin.Write xhr.ResponseBody
bin.Position = 0
bin.SaveToFile save_as
bin.Close
1行目:静的変数宣言(Static)することで、2回目のコード実行時にCreateOjbect生成を不要にしている。
3行目:同じファイル名が存在している場合、既存ファイルを削除する。
4行目:binオブジェクトオープン
5行目:データタイプの選択(1:バイナリデータ 2:テキストデータ)
6行目:binオブジェクトにバイナリデータを書き込む
7行目:位置を先頭に戻す
8行目:ファイルを引数のフルパス名で保存
9行目:binオブジェクトを閉じる
ADODB.Streamの各メソッド、プロパティの説明は以下ページ参照ください。
pdfの基本構造が分かりやすく掲載されているページも下記に紹介しておきます。
番外:JPEGデータのダウンロード
番外として、JPEGデータのダウンロードをする場合の構文も掲載しておきます。
SeleniumBasicは使用していません。
Private Sub Download_jpeg()
Dim save_as As String: save_as = ThisWorkbook.Path & "\sample.jpg"
On Error Resume Next
Static xhr As Object
If xhr Is Nothing Then Set xhr = CreateObject("Msxml2.ServerXMLHTTP.6.0")
xhr.Open "GET", "https://www.ka-net.org/images/logo.jpg"
xhr.setRequestHeader "Pragma", "no-cache"
xhr.setRequestHeader "Cache-Control", "no-cache"
xhr.setRequestHeader "If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT"
xhr.Send
On Error GoTo 0
If (xhr.Status \ 100) - 2 Then Err.Raise 5, , xhr.Status & " " & xhr.StatusText
Static bin As Object
If bin Is Nothing Then Set bin = CreateObject("ADODB.Stream")
If Len(Dir$(save_as)) Then Kill save_as
bin.Open
bin.Type = 1
bin.Write xhr.ResponseBody
bin.Position = 0
bin.SaveToFile save_as
bin.Close
End Sub
以下ホームページを参照させていただきました。