商品ページからボタン一つで情報を取り込むVBAプログラムの作り方(Amazon編③)


【前回の記事】

商品ページからボタン一つで情報を取り込むVBAプログラムの作り方(Amazon編①)
商品ページからボタン一つで情報を取り込むVBAプログラムの作り方(Amazon編②)

前回までの内容で文字データまでの取得ができましたので、今回は商品画像を取得する処理を書いていきたいと思います。

4.商品画像を取得する

まず商品ページを開いた際に表示されている商品画像がありますので、その画像のURLを探してみましょう。

メイン画像のタグについては上図の箇所にあります。見つけられましたでしょうか?

id値「landingImage」というimgタグに商品画像が設定されているのが分かりますね。

このタグの「src」がそのまま商品画像のURLとなっています。

※確認したい場合は、URL部分をコピーしてアドレスバーに貼り付けてみて下さい。

ではこの画像を取得するために幾つか処理を追加していきます。

Option Explicit

Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias _
"URLDownloadToFileA" (ByVal pCaller As LongPtr, ByVal szURL As String, ByVal _
szFileName As String, ByVal dwReserved As LongPtr, ByVal lpfnCB As LongPtr) As LongPtr

'-----------------------------------------------------------------
'現在IEで開いているAmazonの商品ページの情報を、シート状に取得する
'-----------------------------------------------------------------
Sub main()
    Dim objIE As InternetExplorer       'Amazonの商品ページを格納
    Dim sProductName As String          '商品名
    Dim sProductPrice As String         '商品価格
    Dim sProductExplain As String       '商品説明
    
    'IE取得関連
    Dim objShell As Object              'shellオブジェクト格納
    Dim objWindow As Object             'ウィンドウを格納
    Dim vTmp As Variant
    Dim iIdx As Integer
    
    '画像取得関連
    Dim objLiTags As Object             '全liタグを格納
    Dim objLi As Object
    Dim sClassName As String            'タグのクラス名を格納
    Dim sPicURL As String               '画像ファイルのURL
    Dim iPicNum As Integer              '画像番号

----------------省略------------------

    Call URLDownloadToFile(0, objIE.document.getElementById("landingImage").src, _
        ThisWorkbook.path & "\switch_microsd.jpg", 0, 0)
    
End Sub

まずは「Sub main()」の上に「URLDownloadToFile」という宣言を追加しました。

これが画像をダウンロードするために使用する関数となります。

元々は「Windowsに用意されている各種機能を利用するためのシステム関数」で、VBAの機能として最初から使える訳ではありません。

ですが、”どこから呼び出すのか”という「場所」と「名前」を指定してあげることで、以降はVBA内で使える他の関数と同様に使用できる様になります。

この手法を「API宣言」と言います。

続いて、「画像取得関連」のコメント以下5つの変数を定義します。

すぐに使用する訳ではありませんが、後々使うのでここで定義しておいて下さい。

最後に「URLDownloadToFile」を呼び出して画像をダウンロードする処理を行っています。

URLDownloadToFileは2つ目の引数にダウンロード対象のURLを指定し、3つ目の引数に保存先のパス(設定したい画像ファイル名も含めたフルパス)を指定します。他の箇所は上記サンプルの様に「0」で構いません。

今回は保存先に「Thisworkbook.Path」(実行したエクセルと同じ場所)を指定しています。

ではまず、前回の記事の最後にあるコードに、上記処理を追加してそのまま実行してみて下さい。

すると、そのエクセルファイルと同じ場所に「switch_microsd.jpg」という名前で商品画像のファイルが保存されているはずです。

これで画像の保存処理も完成!・・・とは言えませんよね。

画像が一つしか設定されていない場合はこの処理で十分ですが、複数の画像が設定されていた場合は全ての画像を保存したいと思います。

という事で複数画像にも対応できる様に作り変えていきます。

スポンサーリンク

5.複数の画像に対応する

商品ページに複数の画像が存在した時、通常ユーザーが画像を切り替えるためにはどの様にすれば良いでしょうか?

・・・はい、メイン画像の横にあるサムネイルをクリックすれば切り替わりますよね。

むしろ他の画像を見たいだけであればサムネイル画像の上にマウスポインタを置くだけで自動的に切り替わります。

つまりそういったアクションを行うことで、裏でプログラムが動いて自動的に表示する画像を切り替えているという事です。

それを踏まえて、先ほど見たメインに表示されている画像のソース部分をもう一度確認してみましょう。

今度は「img」タグでは無く、もう少し広い範囲でタグをよく見て下さい。

「li」タグのクラス名を見てみると、

image item itemNo0 maintain-height selected

という風になっていますよね。

itemNo0」って何か気になりませんか?「itemNo1」とかあるのかな?って思いますよね。

その後ろにある「selected」というのも”何が選択されている”という意味なんでしょう。

そうです。この「itemNo」というクラス名が付いているタグが、メインに表示されるimgタグが含まれている箇所になります。

では以下の画像を見て下さい。

「itemNo0」は今選択されている1枚目の画像なので「selected」が付いています。

下の方に見える「itemNo1」は2枚目の画像が含まれているliタグです。

2枚目のサムネイル画像をクリックすると、「itemNo1」の方に「selected」が付いて、2枚目の画像が表示される仕組みとなっています。

ではVBAの方に戻り、以下の条件をもとに処理を変えてみます。

  • 複数の画像があった場合に連番を設定する必要があるため、連番用の変数を用意してそれを初期化(0を格納)する。
  • 商品ページ内からliタグを抽出する。
  • クラス名に「itemNo」を含むものがあれば、そのタグの子要素に含まれる「img」タグからsrcの値(画像のURL)を取得する。
  • 連番名を付けて画像を保存する。
  • 連番用の変数を増やす。
  • 全ての画像をダウンロードするため、ループ処理させる。
'    Call URLDownloadToFile(0, objIE.document.getElementById("landingImage").src, _
'        ThisWorkbook.path & "\switch_microsd.jpg", 0, 0)
        
    'liタグから画像URLを抽出し、ダウンロード
    iPicNum = 0
    Set objLiTags = objIE.document.getElementsByTagName("li")
    For Each objLi In objLiTags
        On Error Resume Next
        sClassName = objLi.className
        On Error GoTo 0

        If InStr(LCase(sClassName), "itemno") > 0 Then
            sPicURL = objLi.getElementsByTagName("img")(0).src
            Call URLDownloadToFile(0, sPicURL, ThisWorkbook.path & "\picture_" & iPicNum & ".jpg", 0, 0)
            iPicNum = iPicNum + 1
        End If
    Next

「4.商品画像を取得する」で作った画像ダウンロード部分の処理を消して、上のソースをコピーした後実行してみて下さい。

あ、実行する前にIEの商品ページは一度「更新」して下さいね。

「picture_0.jpg」という名前で、商品画像の1枚目が保存されたと思います。

・・・あれ?

全ての画像を保存する様にしたはずなのになぜか1枚目の画像しか保存されていませんね。

※ここから想像が入っています。違ってたら指摘して下さい。

実は商品ページを開いてすぐの状態では、大きい画像は「1枚目の画像しか読み込まれていない」んです。(ページを開いた直後は2枚目の画像にあたる「itemNo1」のliタグが出現していないという事です。)

恐らく少しでも早く商品ページを読み込ませるために「サムネイル画像」と「1枚目の大きい画像」のみ読み込ませておいて、他の画像を見たいという風に興味を持ってクリックしようとした場合にだけ、随時他の画像を読み込む

という仕様にしているんじゃないかと思います。

今回調べていて初めて分かったことだったのですが、細かい所で頑張ってるんだなーとAmazonの営業努力を感じました。

・・・まぁAmazonの努力は置いといて、これだと一回手動でサムネイルにマウス乗せたりクリックしないと他の画像を取得できないという事になりますよね。

しかしそれだとここまで自動化した意味がありません。

何とかする手段は・・・

もちろんあります

要はサムネイルをクリックして各画像を読み込ませれば良いんです。

ということで先ほどの「For Each」処理の手前に以下の処理を追加します。

'    Call URLDownloadToFile(0, objIE.document.getElementById("landingImage").src, _
'        ThisWorkbook.path & "\switch_microsd.jpg", 0, 0)
    'サムネイル一覧を全てクリックし、タグを出現させる
    Set objLiTags = objIE.document.getElementsByTagName("li")
    For Each objLi In objLiTags
        On Error Resume Next
        sClassName = objLi.className
        On Error GoTo 0

        If InStr(LCase(sClassName), "a-spacing-small item") > 0 Then
            objLi.getElementsByTagName("input")(0).Click
        End If
    Next

    'liタグから画像URLを抽出し、ダウンロード
    iPicNum = 0
    Set objLiTags = objIE.document.getElementsByTagName("li")
    For Each objLi In objLiTags
        On Error Resume Next
        sClassName = objLi.className
        On Error GoTo 0

        If InStr(LCase(sClassName), "itemno") > 0 Then
            sPicURL = objLi.getElementsByTagName("img")(0).src
            Call URLDownloadToFile(0, sPicURL, ThisWorkbook.path & "\picture_" & iPicNum & ".jpg", 0, 0)
            iPicNum = iPicNum + 1
        End If
    Next

サムネイル画像の方は「li」タグで抽出後、「a-spacing-small item」というクラス名が付いているかどうかで判定可能です。

見つかった場合は、その子要素に含まれる「input」タグをクリックすることで画像の読み込みを行っています。

ちなみにそれぞれの「For Each」処理の手前で

「Set objLiTags = objIE.document.getElementsByTagName(“li”)」

と同じ処理が記述されていますが、これは両方とも必要なので2つ目(保存する際のループ側の処理)を消さない様に注意しましょう。

それでは早速、修正後の上記コードを実行してみて下さい。

「picture_0.jpg」、「picture_1.jpg」という二つの画像ファイルが保存されているのが分かると思います。

・・・ただ、サンプルとして用意した商品が悪かったせいで、全く同じSDの画像が保存されてしまったいるので分かりませんね。(笑)

他の商品でもそのまま実行できると思いますので、ちゃんと全ての画像が保存されるかどうかを確認するために別の商品でも試してみて下さい。

6.取得したデータを書き込む

最後は今まで取得してきたデータを、エクセルシート上に書き込むだけですね。

貼り付け方は好きなやり方で組んでもらって構いません。

7.ここまでのコード

ここまでのVBAコードは以下の通りです。

Option Explicit

Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias _
"URLDownloadToFileA" (ByVal pCaller As LongPtr, ByVal szURL As String, ByVal _
szFileName As String, ByVal dwReserved As LongPtr, ByVal lpfnCB As LongPtr) As LongPtr

'-----------------------------------------------------------------
'現在IEで開いているAmazonの商品ページの情報を、シート状に取得する
'-----------------------------------------------------------------
Sub main()
    Dim objIE As InternetExplorer       'Amazonの商品ページを格納
    Dim sProductName As String          '商品名
    Dim sProductPrice As String         '商品価格
    Dim sProductExplain As String       '商品説明
    
    'IE取得関連
    Dim objShell As Object              'shellオブジェクト格納
    Dim objWindow As Object             'ウィンドウを格納
    Dim vTmp As Variant
    Dim iIdx As Integer
    
    '画像取得関連
    Dim objLiTags As Object             '全liタグを格納
    Dim objLi As Object
    Dim sClassName As String            'タグのクラス名を格納
    Dim sPicURL As String               '画像ファイルのURL
    Dim iPicNum As Integer              '画像番号
    
    Dim iRow As Integer
    
    '---------Amazonのページを取得する処理---------
    Set objShell = CreateObject("Shell.Application")

    For Each objWindow In objShell.Windows
        'IEウィンドウの判定
        If InStr(LCase(objWindow.FullName), "iexplore.exe") > 0 Then
            'タイトルにAmazon.co.jpが含まれていれば商品ページと判定
            If InStr(objWindow.document.title, "Amazon") > 0 Then
                Set objIE = objWindow
                Exit For
            End If
        End If
    Next
    
    'Amazonのページが見つからなかった場合の処理
    If objIE Is Nothing Then
        MsgBox "商品ページの取得ができませんでした。"
        End
    End If
    '----------------------------------------------
    
    sProductName = Trim(objIE.document.getElementById("productTitle").innerText)
    sProductPrice = Trim(Replace(objIE.document.getElementById("priceblock_ourprice").innerText, "¥", ""))
    
    '改行ごとに分割し、頭に「●」印を付けて再度結合させる
    vTmp = Split(objIE.document.getElementById("feature-bullets").innerText, vbCrLf)
    For iIdx = 0 To UBound(vTmp)
        If Trim(vTmp(iIdx)) <> "" Then
            sProductExplain = sProductExplain & "●" & Trim(vTmp(iIdx)) & vbCrLf
        End If
    Next
    
    'サムネイル一覧を全てクリックし、タグを出現させる
    Set objLiTags = objIE.document.getElementsByTagName("li")
    For Each objLi In objLiTags
        On Error Resume Next
        sClassName = objLi.className
        On Error GoTo 0

        If InStr(LCase(sClassName), "a-spacing-small item") > 0 Then
            objLi.getElementsByTagName("input")(0).Click
        End If
    Next

    'liタグから画像URLを抽出し、ダウンロード
    iPicNum = 0
    Set objLiTags = objIE.document.getElementsByTagName("li")
    For Each objLi In objLiTags
        On Error Resume Next
        sClassName = objLi.className
        On Error GoTo 0

        If InStr(LCase(sClassName), "itemno") > 0 Then
            sPicURL = objLi.getElementsByTagName("img")(0).src
            Call URLDownloadToFile(0, sPicURL, ThisWorkbook.path & "\picture_" & iPicNum & ".jpg", 0, 0)
            iPicNum = iPicNum + 1
        End If
    Next
    
    '最終行+1を書き込み対象行に設定する
    iRow = Cells(Rows.Count, "A").End(xlUp).Row + 1
    
    Cells(iRow, 1).Value = sProductName
    Cells(iRow, 2).Value = sProductPrice
    Cells(iRow, 3).Value = sProductExplain
End Sub

これで完成に見えますが、動かして見ると一つ問題が残っていることに気付くと思います。

この処理のままでは画像のファイル名が「picture_○.jpg」固定になってしまっているので、実行する度に画像が上書きされてしまうんですね。

次回はこの問題を解消するための処理を追加してみたいと思います。

【次の記事】

商品ページからボタン一つで情報を取り込むVBAプログラムの作り方(Amazon編④)

関連記事と広告

シェアする

  • このエントリーをはてなブックマークに追加

フォローする