【Webスクレイピング】VBAでAmazonの在庫ステータスを取得しよう

私は出版社に勤める、出版人の端くれです。

なので当然、Amazonにおける書籍の在庫ステータスは気になります。Amazonでは、いつのまにか在庫なしになっている場合もありますので、少しだけでも在庫ステータスを感知して置く必要があります。

そこで今回、VBAのIE制御を用いて、Amazonの在庫ステータスを取得するツールを作成しましたので、紹介します。

どんな処理を行う?

初めにどんな処理を行っていくか、簡単に解説します。

流れとしては、

  • Amazonでシートから取得したISBNを検索
  • 結果の一番最初にあるリンク(書籍詳細ページへのリンク)に飛ぶ
  • 書籍詳細ページから在庫ステータスを取得
  • シートに書き込む

となります。

最終的には以下のような画面になります。

はじめに

はじめに、以下のようなExcelシートを作成します。

1列目:書名、2列目:ISBN、3列目:在庫ステータスです。

1列目と2列目を入力しておいてください。

コードの紹介

以下が全コードになります。

Option Explicit
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Sub getInventoryStatus()
    Dim objIE As InternetExplorer
    Dim url As String
    Dim htmlDoc As HTMLDocument
    url = "https://www.amazon.co.jp/" '対象となるURL
    
    'IEを起動し表示させる
    Set objIE = CreateObject("Internetexplorer.Application")
    objIE.Visible = True

    Dim i As Long, lastRow As Long
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row

    'ISBNの数だけループさせる
    For i = 2 To lastRow
        'Amazonのページを表示
        objIE.navigate (url)
        Call IEの読み込み待ち(objIE)
    
        Set htmlDoc = objIE.document
        
        'Amazonの検索窓を取得→ISBN(cells(i,2))を入力→検索ボタンをクリック
        Dim serchForm As HTMLInputTextElement
        Set serchForm = htmlDoc.getElementById("twotabsearchtextbox")
        serchForm.Value = Cells(i, 2)
        Dim btnSerch As HTMLFormElement
        Set btnSerch = htmlDoc.getElementsByClassName("nav-input")(0)
        btnSerch.Click
        
        '検索結果の画面を取得し、最初のAnchor(リンク)を取得し、そのリンクに飛ぶ
        Call IEの読み込み待ち(objIE)
        Set htmlDoc = objIE.document
        Dim a As HTMLAnchorElement
        Set a = htmlDoc.getElementsByClassName("a-link-normal a-text-normal")(0)
        objIE.navigate (a.href)
        
        '在庫状況のテキストをcells(i,3)に書き込む
        Call IEの読み込み待ち(objIE)
        Set htmlDoc = objIE.document
        Cells(i, 3).Value = htmlDoc.getElementById("availability").outerText
    Next
End Sub

Sub IEの読み込み待ち(objIE)
  Dim timeOut As Date

  '完全にページが表示されるまで待機する
  timeOut = Now + TimeSerial(0, 0, 20)

  Do While objIE.Busy = True Or objIE.readyState <> 4
    DoEvents
    Sleep 1
    If Now > timeOut Then
      objIE.Refresh
      timeOut = Now + TimeSerial(0, 0, 20)
    End If
  Loop

  timeOut = Now + TimeSerial(0, 0, 20)

  Do While objIE.document.readyState <> "complete"
    DoEvents
    Sleep 1
    If Now > timeOut Then
      objIE.Refresh
      timeOut = Now + TimeSerial(0, 0, 20)
    End If
   Loop
End Sub

コードの解説

では、コードを解説していきます。途中で、若干のHTMLに関する知識が必要となりますが、スクレイピングに必要な程度の簡単なものですので、HTMLの苦手な方も頑張って取り組んでみてください。

Option Explicit
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

この部分は呪文のようなコードです。意味を理解せずとも、とりあえず記述しておきましょう。一応、簡単に意味を説明しておきます。VBAでIEを制御する場合、IEがWebページにアクセスしたら、そのページが読み込まれるまで待つ処理が必要になります。その処理はWindowsの機能であるSleepを用いる必要があるため、それを使用するための処理が記述しています。

Sub getInventoryStatus()
    Dim objIE As InternetExplorer
    Dim url As String
    Dim htmlDoc As HTMLDocument
    url = "https://www.amazon.co.jp/" '対象となるURL

この部分では、変数の宣言を行い、スクレイピングの対象となるAmazonのページのURLを指定しています。

'IEを起動し表示させる
    Set objIE = CreateObject("Internetexplorer.Application")
    objIE.Visible = True
 
    Dim i As Long, lastRow As Long
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row

この部分では、IEオブジェクトを作成し、objIEに格納し、それを表示させています(visible=True)。それに加えて、カウンタ変数と最終行を示す変数を宣言しています。

    For i = 2 To lastRow
        'Amazonのページを表示
        objIE.navigate (url)
        Call IEの読み込み待ち(objIE)
     Set htmlDoc = objIE.document

ここから、シートに入力されている書籍の数だけ処理をループさせていきます。まずはAmazonの最初のページを表示させています。IEにページを読み込ませるまで処理を中断する必要があるので、IEの読み込み待ち というサブプロシージャを用いています。この処理については後述します。その後、その読み込まれたページをhtmlDocという変数にセットしています。このhtmlDocから各種エレメントを取得していきます。

        'Amazonの検索窓を取得→ISBN(cells(i,2))を入力→検索ボタンをクリック
        Dim serchForm As HTMLInputTextElement
        Set serchForm = htmlDoc.getElementById("twotabsearchtextbox")
        serchForm.Value = Cells(i, 2)
        Dim btnSerch As HTMLFormElement
        Set btnSerch = htmlDoc.getElementsByClassName("nav-input")(0)
        btnSerch.Click

この部分では、Amazonのページの上位置する検索窓のエレメントを取得し、そこにISBNを入力しています。そして、検索を行うボタンのエレメントを取得し、そのボタンをクリックするという処理を行っています。これでISBNで検索することができます。

エレメントを取得する際には、getElementByIDとgetElementByClassNameを用いています。これは、HTMLの知識のない方には難しい部分になります。

Amazonの検索窓には、以下の画像のようなidとclassが設定されています。オレンジの文字がid、青の文字がclassです。idとclassというのは、HTML上における目印のようなものと捉えてくださって構いません。

ちなみに、どのようなidやclassが指定されているかは、Chromeを使用されている方だと、Chromeメニューの、「その他のツール」→「デベロッパーツール」を使用することで確認できます。

htmlDocからgetElementByIDとgetElementByClassNameによって、これらidやclassが設定されたエレメントを探しだし、取得します。今回の画像だと、id="twotabsearchtextbox"と指定されていますので、それをhtmlDocからgetElementByIdで指定し、取得しています。また、id名の冒頭の#およびclass名の冒頭.(ドット)は、それぞれがid名・class名を表すための接頭語のようなものです。なので、getElemetByIdなどでidを設定する際には、冒頭の#は必要ありません。

ちなみに、HTMLでは、基本的に、1つのページには複数のidを記述することができません。つまり、twotabsearchtextboxというidが設定されたエレメントは、このページにはこれしかありません。それに対して、class名は、同じものを1つのページに複数設定できてしまいます。なので、取得したいエレメントにidが設定されていた場合は、それを指定するようにしましょう。

そして、検索窓のエレメントが取得できましたので、そのvalueプロパティに、ISBNを設定します。これで、検索窓にISBNが入力された状態になります。そして、検索を行うためのボタンのエレメントを取得し、メソッド:クリックを実行し、検索結果のページを表示させます。この検索を行うためのボタンには、idが設定されておらず、class="nav-input"のみが設定されています。

この場合、getElementByClassNameを用います。しかし、先でも説明しましたが、id名はユニークなものであるのに対して、class名は同じものが複数存在します。なので、class名を指定しただけでは目的のエレメントを取得できません。

そのため、指定したいエレメントが、そのページ上で何番目に位置するかを指定する必要があります。HTMLソースを確認し、そのclass名を持つものの何番目に該当するかを確認してください。

今回の場合はclass="nav-input"をの中では最初に位置するものだったので、getElementsByClassName("nav-input")(0)で要素を取得しています。

こういった、DOMと呼ばれる部分の操作は、HTMLを知らない方には難解です。これについては、以下のサイトに詳しいので、参照してください。

DOMとは | IE操作の自動化
DOM(Document Object Model)は、html・head・body・p・aなどのHTMLドキュメント要素にアクセスして取得や操作ができる仕組みのことです。
        '検索結果の画面を取得し、最初のAnchor(リンク)を取得し、そのリンクに飛ぶ
        Call IEの読み込み待ち(objIE)
        Set htmlDoc = objIE.document
        Dim a As HTMLAnchorElement
        Set a = htmlDoc.getElementsByClassName("a-link-normal a-text-normal")(0)
        objIE.navigate (a.href)

検索結果が表示されると、IEの読み込み待ちを行い、htmlドキュメントを再度取得します。この処理は、ページが遷移する度に必要となるものですので必ず行ってください。ISBNで検索すると、かならず目的の書籍が最初に表示されます(ISBNはユニークな値です)。検索結果の最初のエレメント(getElementsByClassName("s-access-detail-page")(0))を取得し、そのエレメントのプロパティ:href(書籍詳細ページのリンク)からリンクを取得し、そこに飛びます。

        '在庫状況のテキストをcells(i,3)に書き込む
        Call IEの読み込み待ち(objIE)
        Set htmlDoc = objIE.document
        Cells(i, 3).Value = htmlDoc.getElementById("availability").outerText
    Next

そして、cells(i,3)に在庫ステータスを示すエレメントのテキストを入力。次の書籍にループします。これで処理は終了です。

Sub IEの読み込み待ち(objIE)
  Dim timeOut As Date
 
  '完全にページが表示されるまで待機する
  timeOut = Now + TimeSerial(0, 0, 20)
 
  Do While objIE.Busy = True Or objIE.readyState &amp;lt;&amp;gt; 4
    DoEvents
    Sleep 1
    If Now &amp;gt; timeOut Then
      objIE.Refresh
      timeOut = Now + TimeSerial(0, 0, 20)
    End If
  Loop
 
  timeOut = Now + TimeSerial(0, 0, 20)
 
  Do While objIE.document.readyState <> "complete"
    DoEvents
    Sleep 1
    If Now > timeOut Then
      objIE.Refresh
      timeOut = Now + TimeSerial(0, 0, 20)
    End If
   Loop
End Sub

このプロシージャに関しては、以下のサイトから転載しました。そちらも参照してください。
https://www.vba-ie.net/code/ieview2.html

まとめ

今回は、Amazonの在庫ステータスをVBAで取得する方法を紹介しました。これを改変すると、ランキング情報などを取得することもできますし、他のサイトのスクレイピングもできるようになります。ぜひ参考にしてください。

タイトルとURLをコピーしました