Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

VBAプログラム開発、スクレイピング・ページネーション対応する【3】書籍一覧取得VBAと全ページアクセスVBAを組み合わせる

前回記事にて書籍一覧ページのページネーションから次ページを特定して、全ページに順番にアクセスする処理を作成しました。

今回は、書籍情報の取得VBAと、ページネーションURL取得による全ページアクセスのVBAを組み合わせて、全ページの書籍情報を取得出来るようにします。

今回の目的

全ページの書籍情報を取得してExcelワークシートへ集約できるようにする

なぜやるか

書籍情報取得VBAは指定のページのみしかデータが取得できていなかったので、次ページURLを繰り返し取得するVBAを組み合わせて、全ページの全データを取得できるようにするため

やりたいこと

  • 2つのVBAを組み合わせて書籍データを取得しつつ、次のページへアクセスする…を繰り返す

やったこと

  • 作成済みのVBAを組み合わせる方法を考える
  • ベースとなるVBAを決定し、他を呼び出す
  • 全データを出力できるよにする

実施内容

どうやってVBAコードを組み合わせるか

繰り返し中に書籍情報も取得すればいい

WebページからHTML取得、HTMLから書籍情報を取得。

これをページ毎に実施すれば完了です。

と、この2工程だけを実施すれば簡単に作成できそうです。

「ページ毎に繰り返し処理」を前回作成したので、繰り返しの中に書籍一覧取得VBAを組み込みできれば、すぐ完成しそうな気がしていました。

 

重複内容が多い 

バラバラに作成していたコードを見直して気がついたことは、同じ事をしている…ということです。どちらもスクレイピングしてデータを取得しているので、まぁ当然なわけですが。

そのまま組み合わせるには重複ポイントが多すぎるので、片方のコードをベースに、必要な情報だけを引数としてわたせるような形で作成していきます。

次ページを取得するVBAをベースにしておき、HTML取得をした時に書籍一覧要素を取り出す処理を別のプロシージャにしておいて呼び出せるようにします。

 

プロシージャからプロシージャを呼び出す

コードを呼び出す

これは既に一つ組み込んでいました。WebページのHTML要素の展開を待つプロシージャを呼び出しています。

# 呼び出し時のコード

Call WaitResponse(objIE) '読み込み待ち

callは省略できますが、記載しておいたほうが分かりやすいでしょう。

 

# 呼び出し先

Sub WaitResponse(objIE As Object) 'Webブラウザ表示完了待ち
 Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE '読み込み待ち
  DoEvents
 Loop
End Sub

呼び出し元で(objIE)と引数を設定していたので、それを受け取って処理していました。

このような感じで、ページネーションのループ内に書籍一覧を取得するプロシージャも呼び出せるようにします。

 

プロシージャ呼び出しを使う

まずは、「書籍一覧表示のデータを取得する」を記載しているプロシージャを呼び出せるようにしておきます。

# ページネーションVBAをベースに作成

Sub getBookdatas()

 'オブジェクト設定(抜粋)
  '作業ワークシート
  Dim SWSheet As Worksheet
  Set SWSheet = ThisWorkbook.Worksheets("テスト")
  
'繰り返し処理
  Dim i As Integer
  
i = 1

 
'最終ページまで繰り返す
 Do Until OpenPage = ""

  'WebサイトからHTML取得  

  objIE.navigate OpenPage
  Call WaitResponse(objIE)
  Set htmlDoc = objIE.document
  OpenPage = ""

  '書籍情報取得処理
  Call getBookList(SWSheet, htmlDoc, i)

  'ページネーションから次ページURLを取得
  ~ 略 ~
 Loop

 objIE.Quit
 MsgBox "データ取得が完了しました。"

End Sub

解説用に一部コードを省略しています。前回作成した全ページを順番に取得するコードに書籍情報を取得するgetBookListという名前のコードを呼び出せるようにしました。

HTML要素・書き出しワークシート・セル番地を指定する番号を呼び出し先で使用するので、引数として設定しました。

 

続いて、Call先となるgetBookListのコードを確認します。

# 書籍情報取得

Sub getBookList(SWSheet As Worksheet, htmlDoc As HTMLDocument, i As Integer)
 Dim Bookdata As HTMLDivElement 'レコード単位データ
 Dim detailField As HTMLDivElement '詳細フィールドデータ

 For Each Bookdata In htmlDoc.getElementsByClassName("book-table__list")
  SWSheet.Cells(i + 1, 1).Value = i
  Set detailField = _

   Bookdata.getElementsByClassName("book-table__list--detail")(0)

  SWSheet.Cells(i + 1, 2).Value = _

   detailField.getElementsByClassName("list-book-title")(0).innerText
  i = i + 1
 Next Bookdata

End Sub

元々書籍情報を取得するためのコードとして作成していましたが、引数を渡して処理するという手順が加わったので、受け取った引数を意識して初めから書きました。

動作確認の為、i の連番処理ができていることと、タイトル名のみを取得して表示できるようにしてみました。

 

この状態で、まずデータが取得できるかを確認します。 

f:id:Fippiy:20190614170951j:plain

全ページタイトル取得

3ページに跨がっていた書籍情報をページ毎に取得し一覧化できました。

繰り返し処理によって2ページ目・3ページ目のデータも続けて取得して、タイトル名が表示できています。変数iも連続して処理できているので、2ページ目に遷移しても継続処理されています。

 

ここまで出来れば、残りの情報を取得するコードを追記すれば全データが取得できそうです。

 

全てのデータを表示できるようにする

残りのデータ取得についても反映させます。

# 書籍情報取得(ForEachに追記)

For Each Bookdata In htmlDoc.getElementsByClassName("book-table__list")

 '--detail情報からデータ取得
  '--detailを取得
  Set detailField = Bookdata.getElementsByClassName("book-table__list--detail")(0)
  'タイトル名取得
  SWSheet.Cells(i + 1, 2).Value = _

   detailField.getElementsByClassName("list-book-title")(0).innerText

  '詳細テキスト
  SWSheet.Cells(i + 1, 3).Value = _

   detailField.getElementsByClassName("list-book-detail")(0).innerText

  '詳細ページURL
  BookdataURL = detailField.getElementsByTagName("a")(0) 'URL取得
  SWSheet.Cells(i + 1, 4).Value = BookdataURL '取得URL反映

  'Bookdata_ID取得
  BookdataURLSplit = Split(BookdataURL, "/") 'URL要素分割
  BookdataURLBound = UBound(BookdataURLSplit) 'URL要素数確認
  BookdataID = BookdataURLSplit(BookdataURLBound) 'ID番号取得
  SWSheet.Cells(i + 1, 1).Value = BookdataID
 '--detail情報からデータ取得ここまで

 '画像処理

  Set BookdataImg = Bookdata.getElementsByTagName("img")(0) '画像取得
  ImgURL = BookdataImg.src
'画像URL
  Set ActCell = SWSheet.Cells(i + 1, 5)
'出力セル

  '画像出力セルのピクセルを指定して表示
  SWSheet.Shapes.AddPicture _
   fileName:=ImgURL, _
    LinkToFile:=True, _
    SaveWithDocument:=True, _
    Left:=ActCell.Left, _
    Top:=ActCell.Top, _
    Width:=100, _
    Height:=100

 '画像処理ここまで

 '列番号処理
 i = i + 1
Next Bookdata

詳細ページURLや画像などについて追加しました。処理している内容は書籍一覧取得VBA作成時の物です。変数名は若干変更しています。

データ取得についてはタイトル名ですでに取得できていることは確認していますが、改めて全て取得できることを確認します。

f:id:Fippiy:20190615104626j:plain

データ取得テスト

全ページの全データを対象に取得できました。

確認用の為、確認専用シートでの表示であり、行間も短くしていました。

出力ワークシートを変更して、再度データ取得します。

f:id:Fippiy:20190615105002j:plain

データ出力確認

初めに書籍一覧取得VBAを作成していた時のワークシートへ出力できるように変更しました。

Set SWSheet = ThisWorkbook.Worksheets("スクレイピング")

ワークシート名を指定して変数に格納しているので1箇所変更するのみです。

f:id:Fippiy:20190615105222j:plain

書籍一覧取得(最後)

全ページ取得VBAとしているので、最終ページのデータまで取得できていることを確認します。(上記画像では47行目まで取得できている)1行目はタイトル名なので、46件のデータが取得できています。

f:id:Fippiy:20190615105342j:plain

書籍一覧取得(全体像)

全件取得結果イメージです。このように、1ページ目の最大20件より多くのデータが一度に取得できています。(上記画像は30件分です)

 

以上で、複数ページに跨がっての書籍情報一覧取得ができるようになりました。