SeleniumBasicでダウンロード利用その1 usage_download

リファレンス

 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データリンクを取得する方法です。大まかなコードの構成は、以下のとおりです。

STEP
Usage_Download_EleLink

・PDFデータのリンクデータ要素をキャッチ
・Download_EleLink関数の呼出し(引数:リンク要素、保存フルパス)

STEP
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

以下ホームページを参照させていただきました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

VBAを中心とした自動化、効率化の手法を紹介しています。現在は、SeleniumBasicのexamplesを紹介しています。その内、SeleniumBasic以外の手法も掲載したいと思っております。

目次