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

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

VBAプログラム開発、スクレイピング・ページネーション対応する【2】次ページに遷移を繰り返し、全ページにアクセスする

前回はページネーションからURLを取得できるようにしました。

今回は、「次のページ」のURLを特定し、実際に次のページの情報を取得します。ページ遷移毎に次のページのURLを取得して最後のページまで自動で移動しつつデータ取得できるようにしていきます。

今回の目的

次のページURLをたどりながら全ページのデータを取得する

なぜやるか

次ページURL情報取得ができているので、全ページを自動化で継続してデータ取得できるようにするため

やりたいこと

  • ページネーションURLから次ページのURLを特定する
  • 1ページだけでなく、存在する全ページのデータを取得する

やったこと

  • 次ページURLを特定する文字を決定する
  • 指定文字で次ページURLが取得できるようにする
  • 繰り返し処理を使用し、全ページのデータを取得する

実施内容

次のページへのURLを取得する 

次のページリンクを特定する

ページネーションからURLを取得するところまでは作成できました。

後は「次のページ」へのURLはどれか?を判定する必要が有ります。

判定ができれば、次に開くページが指定でき、開いたページのデータ取得をする…を繰り返しできるようにすれば1ページのみ対応だったのが、全ページ対応になります。

そのためにも次ページへのURLがどれかを判別する必要があります。 

取得出来ているaタグはこちらです。 

f:id:Fippiy:20190613111815j:plain

取得URL

HTMLでも確認しておきます。

# HTML(最初のページ)

<ul class="pagination" role="navigation">
 <li class="page-item disabled" aria-disabled="true" aria-label="« 前へ">
  <span class="page-link" aria-hidden="true">‹</span>
 </li>
 <li class="page-item active" aria-current="page">

  <span class="page-link">1</span>

 </li>
 <li class="page-item">

  <a class="page-link" href="~/book?page=2">2</a>

 </li>
 <li class="page-item">

  <a class="page-link" href="~/book?page=3">3</a>

 </li>
 <li class="page-item">
  <a class="page-link" href="~/book?page=2" rel="next" aria-label="次へ »">›</a>
 </li>
</ul>

ページネーションとして取得する部分のHTMLにはリンク情報がありました。3ページ構成の場合は水色の3箇所です。

このうち、次のページへのリンク情報に付与されているrel="next"という標記があるので、これを判定材料とすることにしました。

 

rel="next"があることを判定する

URLを取得時に、次のページへのリンクであるということを判定します。次ページURLを3列目に表示します。

f:id:Fippiy:20190613145015j:plain

次ページリンク判定結果

このように、次ページリンクである、すなわちrel="next"が含まれたリンク情報であることを判定できれば次ページとして指定できます。

If文による次ページリンクの判定を書いてみました。

# ページネーション取得

Dim Pagination As HTMLUListElement 'ページネーションデータ
Dim PagiLink As HTMLAnchorElement '次ページリンク
 
'ページネーションクラス名取得
Set Pagination = htmlDoc.getElementsByClassName("pagination")(0)
 

If Not Pagination Is Nothing Then
 'ページネーションがある場合は取得処理
 For Each PagiLink In Pagination.getElementsByTagName("a")
  Cells(i, 2).Value = PagiLink.outerHTML
  If InStr(PagiLink.outerHTML, "rel=""next") > 0 Then
   OpenPage = PagiLink.href
  End If
 Cells(i, 3).Value = OpenPage
 i = i + 1
 Next PagiLink

End If

ページネーション情報を取得して、そこからaタグ情報を取得します。ここまでは今まで通りです。

そして、aタグ情報を受け取ったPagiLink変数に対してrel="next"という文字が含まれているかどうかを確認するようにしました。

rel="next"がある場合は次ページへのリンクですので、OpenPageに次のページであるURLを格納しています。○という判定結果をExcelで出力していましたが、最終的には次ページに移動できればいいので、URL名が一端表示出来るようにしました。

 

ページネーション情報があるかどうかの判定文も変更しました。

If Not Pagination Is Nothing Thenとなっています。

Pagination Is Nothingでは、Paginationという変数がNothingの時。つまり、ページネーション変数がない場合です。これにNotが付いているので日本語で直接書くと「否定(ページネーション変数がない場合)」となっているので結果としてページネーションがある場合を指定しています。

これは、ページネーションがない場合に対しての処理がないので、ページネーションがある場合のみを記述するためにこういった記述に変更しています。

ページネーションがない場合は、次のページが存在しない為、そもそも次のページの情報を探す必要がないからです。

f:id:Fippiy:20190613151154j:plain

取得結果

ページネーションURLを取得し、次ページURLを取り出して個別に表示できました。

このURLを次のスクレイピングページとしてセットしてまたページネーション情報を取得して…と繰り返せば順番にページ遷移できそうです。

 

全ページの情報を取得する 

次ページURLが取得できるようになったので、次のページを表示して同様にスクレイピングを行いまたその次のページのURLを取得できるようにします。

 

繰り返し処理を追加して、次のページでも判定できるようにしました。サブプロシージャを除く全コードを記載します。

# スクレイピングコード(繰り返し処理)

Sub pagecheck()

 'オブジェクト設定

 'IEオブジェクト

 Dim objIE As InternetExplorer
 Set objIE = CreateObject("Internetexplorer.Application")
 objIE.Visible = False

 'HTMLオブジェクト
 Dim htmlDoc As HTMLDocument 'HTML全体
 Dim Pagination As HTMLUListElement 'HTMLページネーション
 Dim PagiLink As HTMLAnchorElement '次ページリンク

 'ワークシート

 Dim SWSheet As Worksheet 'ScrapingWorksheet
 Set SWSheet = ThisWorkbook.Worksheets("テスト")

 

 '最初に開くページ
 Dim OpenPage As String
 OpenPage = "https://protected-fortress-61913.herokuapp.com/book"

 Dim i As Integer 'Excel行表示番号
 Dim page As Integer 'ページ数Excel表示用
 i = 2 'Excelの2行目から出力するので2から
 page = 1 'Excelの1列目に表示するページ数

 '繰り返し処理開始

 '表示するページのURLが変数にセットされていれば処理を続ける
 Do Until OpenPage = ""

  'URLを開いてデータを取得

  objIE.navigate OpenPage 'IEでURLを開く
  Call WaitResponse(objIE) '読み込み待ち
  Set htmlDoc = objIE.document 'objIEで読み込まれているHTMLドキュメントをセット
  OpenPage = "" 'OpenPageURLの初期化

  'クラス名(pagination)の取得
  Set Pagination = htmlDoc.getElementsByClassName("pagination")(0)

  

  'ページネーションデータがある場合に処理

  If Not Pagination Is Nothing Then
   For Each PagiLink In Pagination.getElementsByTagName("a")
    Cells(i, 1).Value = page
    Cells(i, 2).Value = PagiLink.outerHTML

    '次ページリンクであれば、URLを取得

    If InStr(PagiLink.outerHTML, "rel=""next") > 0 Then
     OpenPage = PagiLink.href '次ページURLをOpenPageにセットしておく
     Cells(i, 3).Value = OpenPage

    End If
    i = i + 1
   Next PagiLink
  End If

  page = page + 1
 Loop

 '繰り返し開始へ戻る(繰り返し条件が終了すれば次へ)

 

 objIE.Quit 'objIEを終了させる
 MsgBox "データ取得が完了しました。"

End Sub

初めに最初に開くURLは個別に設定しておき、「URLからサイトを開いてページネーションデータを取得して、次ページURLを取得する」までを繰り返し処理の中に入れました。繰り返し時に次のURLが設定されているので、同様の処理を繰り返します。

f:id:Fippiy:20190614134221j:plain

ページネーション繰り返し

このようになりました。

ページ単位で取得した情報が分かりやすくなるようにページ番号をつけています。

1ページ目のデータを取得した中に次ページのURLが見つかっているので、このURLにアクセスして2ページ情報を取得。さらに3ページ目も取得しています。

最終ページには次ページURLがないので、繰り返し条件にあてはまらずにループからぬけています。

 Do Until OpenPage = ""

ループ処理の開始部分です。

Until OpenPage ="" となっています。OpenPageが""となればループは終了します。

OpenPageには次ページのURLが入るようにしているので、次ページがない=最終ページまでデータ取得ができればループは終了します。

 OpenPage = "" 'OpenPageURLの初期化

HTML要素の取り込み後、最後にOpenPage=""としています。次のページが存在した場合は、

 OpenPage = PagiLink.href '次ページURLをOpenPageにセットしておく

次のページのURLをセットする場所があるのでURLが格納されます。

しかし、次のページがない場合はこの処理は実施されません。初期化がない場合OpenPageには開いたページのURLが残ったままとなり、同じページを永遠と繰り返す為に、初期化処理をしました。

 

ここまでくれば、開いたページ毎に次のページのURLがどこかを探しながら次のページに移動して、また次のページで…と繰り返しができるようになっていますね。

全ページにアクセスできる状態は作成できました。

f:id:Fippiy:20190614134221j:plain

ページアクセス情報

しかし、この情報はあくまで次のページのURLを探してアクセスできればいいデータです。実際にはExcel上に表示させる必要はなく、全ページにアクセスさえできればいいのです。

 

そして、実際に欲しい情報は表示したページの書籍情報です。こちらは初めに一覧情報を取得する処理として作成しました。

 

これら2つのVBAコードを組み合わせて、ページ毎アクセスとページ内書籍データ取得ができれば、全ページの書籍情報を取得できそうです。

こちらを次回作成しようと思います。