【Excel VBA×Selenium】無限スクロールのページからデータを取得する方法|最下部まで自動スクロール

みなさんこんにちは。

Excel VBAとSeleniumを使ってWebスクレイピングをしていると、ページを下にスクロールするたびに新しいデータが表示されるWebサイトに遭遇することがあります。

例えば、求人情報サイトや商品一覧などでは、画面の最下部までスクロールすると、自動的に次のデータが読み込まれる場合があります。

このようなWebサイトでは、最初に表示されているデータだけを取得しても、すべての情報を取得することができません。

今回は、Excel VBAとSeleniumを使って、無限スクロールのページからデータを取得する方法についてご紹介したいと思います。

無限スクロールとは

無限スクロールとは、Webページを下にスクロールすることで、新しいデータが自動的に追加表示される仕組みのことです。

通常のページネーションとは異なり、「次へ」ボタンなどをクリックしなくても新しいデータが表示されます。

ただし、スクロールした直後はデータの読み込みが完了していない場合があります。

そのため、Seleniumを使用する場合は、スクロール処理だけではなく、データの読み込み待機や終了判定を組み合わせる必要があります。

Selenium VBAで無限スクロールを実行するためのサンプルWebページ

今回作成する処理

今回は、以下のWebサイトを使用して動作を確認します。

https://quotes.toscrape.com/scroll

今回作成する処理の流れは以下の通りです。

  1. Google Chromeを起動する
  2. 対象のWebページを開く
  3. 現在表示されているデータの件数を取得する
  4. ページの最下部までスクロールする
  5. 新しいデータが読み込まれるまで待機する
  6. スクロール前後のデータ件数を比較する
  7. データ件数が増えなくなるまで処理を繰り返す
  8. 取得したデータをExcelへ出力する

ポイントは、スクロール回数を固定するのではなく、取得できたデータの件数を比較しながら終了を判定することです。

サンプルコード

以下は、無限スクロールのページからデータを取得し、Excelへ出力するサンプルコードです。

今回は、データが増えなくなった場合でも、すぐには処理を終了しないようにしています。

Option Explicit

Sub GetInfiniteScrollData()

    Dim driver As New Selenium.ChromeDriver
    Dim items As Selenium.WebElements
    Dim item As Selenium.WebElement
    Dim ws As Worksheet

    Dim beforeCount As Long
    Dim afterCount As Long
    Dim stopCount As Long
    Dim scrollCount As Long
    Dim waitCount As Long
    Dim outputRow As Long

    On Error GoTo ErrorHandler

    '========================================
    ' 出力先のワークシートを設定する
    '========================================
    Set ws = ThisWorkbook.Worksheets("Sheet1")

    ' 以前の取得結果を削除する
    ws.Range("A:B").ClearContents

    ' 見出しを設定する
    ws.Cells(1, 1).Value = "名言"
    ws.Cells(1, 2).Value = "著者"

    '========================================
    ' Chromeを起動する
    '========================================
    driver.Start "chrome"

    '========================================
    ' 対象のWebページを開く
    '========================================
    driver.Get "https://quotes.toscrape.com/scroll"

    '========================================
    ' 最初のデータが読み込まれるまで待機する
    '========================================
    For waitCount = 1 To 20

        ' 現在表示されているデータ件数を取得する
        beforeCount = driver.FindElementsByCss(".quote").Count

        ' 1件以上取得できれば待機処理を終了する
        If beforeCount > 0 Then Exit For

        ' 500ミリ秒待機する
        driver.Wait 500

    Next waitCount

    ' データを取得できなかった場合は終了する
    If beforeCount = 0 Then

        MsgBox "データを取得できませんでした。", vbExclamation
        GoTo ExitProc

    End If

    '========================================
    ' 最下部まで自動スクロールする
    '========================================
    For scrollCount = 1 To 40

        ' ページの最下部までスクロールする
        driver.ExecuteScript _
            "window.scrollTo(0, document.documentElement.scrollHeight);"

        '========================================
        ' 新しいデータの読み込みを待機する
        '========================================
        afterCount = beforeCount

        For waitCount = 1 To 10

            ' 500ミリ秒待機する
            driver.Wait 500

            ' スクロール後のデータ件数を取得する
            afterCount = driver.FindElementsByCss(".quote").Count

            ' 件数が増えた場合は待機を終了する
            If afterCount > beforeCount Then Exit For

        Next waitCount

        '========================================
        ' 取得件数を確認する
        '========================================
        Debug.Print "スクロール回数:" & scrollCount & _
                    " / 取得件数:" & afterCount

        '========================================
        ' スクロール前後の件数を比較する
        '========================================
        If afterCount > beforeCount Then

            ' 件数が増えた場合はカウンターを初期化する
            stopCount = 0

        Else

            ' 件数が増えなかった場合は加算する
            stopCount = stopCount + 1

        End If

        ' 次回比較するための件数を更新する
        beforeCount = afterCount

        '========================================
        ' スクロール処理の終了判定
        '========================================
        ' 3回連続で件数が増えなければ終了する
        If stopCount >= 3 Then Exit For

    Next scrollCount

    '========================================
    ' 読み込んだデータを取得する
    '========================================
    Set items = driver.FindElementsByCss(".quote")

    ' Excelへの出力開始行を設定する
    outputRow = 2

    '========================================
    ' 取得したデータをExcelへ出力する
    '========================================
    For Each item In items

        ' 名言をA列へ出力する
        ws.Cells(outputRow, 1).Value = _
            item.FindElementByCss(".text").Text

        ' 著者をB列へ出力する
        ws.Cells(outputRow, 2).Value = _
            item.FindElementByCss(".author").Text

        ' 次の行へ移動する
        outputRow = outputRow + 1

    Next item

    '========================================
    ' 処理完了を通知する
    '========================================
    If stopCount >= 3 Then

        MsgBox items.Count & "件のデータを取得しました。", _
               vbInformation, "取得完了"

    Else

        MsgBox items.Count & "件を取得しましたが、" & _
               "最大スクロール回数に達しました。", _
               vbExclamation, "取得結果の確認"

    End If

ExitProc:

    ' Chromeを終了する
    On Error Resume Next
    driver.Quit
    On Error GoTo 0
    Exit Sub

ErrorHandler:

    ' エラーが発生した場合は内容を表示する
    MsgBox "エラーが発生しました。" & vbCrLf & _
           Err.Description, vbExclamation

    Resume ExitProc

End Sub

コードの解説

ここからは、今回のコードで重要な部分について解説していきます。

現在表示されているデータ件数を取得する

まず、以下のコードで現在表示されているデータの件数を取得しています。

beforeCount = driver.FindElementsByCss(".quote").Count

FindElementsByCssは、指定したCSSセレクターに一致する要素をまとめて取得するメソッドです。

今回は、quoteというクラス名が設定された要素を取得しています。

この取得件数を基準として、スクロール後にデータが追加されたかどうかを確認します。

Chrome開発者ツールで無限スクロールページのquote要素を確認した画面

ページの最下部までスクロールする

ページの最下部まで移動するには、以下のコードを使用します。

driver.ExecuteScript _
    "window.scrollTo(0, document.documentElement.scrollHeight);"

ExecuteScriptを使用すると、SeleniumからJavaScriptを実行することができます。

今回使用しているscrollHeightは、ページ全体のコンテンツの高さを取得するプロパティです。

この値をスクロール位置に指定することで、ページの最下部まで移動できます。

新しいデータが読み込まれるまで待機する

無限スクロールでは、スクロール直後にデータが表示されるとは限りません。

そのため、以下のコードで読み込みが完了するまで待機しています。

For waitCount = 1 To 10

    ' 500ミリ秒待機する
    driver.Wait 500

    ' 現在のデータ件数を取得する
    afterCount = driver.FindElementsByCss(".quote").Count

    ' 件数が増えた場合は待機を終了する
    If afterCount > beforeCount Then Exit For

Next waitCount

今回は、500ミリ秒ごとに取得件数を確認し、最大5秒間待機するようにしています。

件数が増えた場合は、その時点で待機処理を終了します。

このようにすることで、データの読み込みに時間がかかる場合にも対応しやすくなります。

データ件数を比較する

続いて、スクロール前後の件数を比較します。

If afterCount > beforeCount Then

    ' 件数が増えた場合は初期化する
    stopCount = 0

Else

    ' 件数が増えなかった場合は加算する
    stopCount = stopCount + 1

End If

件数が増えていれば、新しいデータが追加されたと判断できます。

一方、件数が増えていない場合は、stopCountを加算しています。

データが増えなくなったら終了する

最後に、以下のコードでスクロール処理の終了を判定しています。

If stopCount >= 3 Then Exit For

今回は、3回連続でデータ件数が増えなかった場合に処理を終了します。

1回だけ件数が増えなかった場合は、再度スクロール処理を実行する仕組みです。

これにより、一時的な読み込み遅延によって処理が終了してしまうことを防ぎやすくなります。

また、最大スクロール回数を40回に設定することで、無限ループを防止しています。

実行結果

今回のサンプルサイトでは、最初に一部のデータが表示され、スクロールすることで新しいデータが追加されます。

VBAを実行すると、イミディエイトウィンドウにスクロール回数と取得件数が表示されます。

すべてのデータを正常に読み込めた場合は、100件の名言と著者をExcelへ出力できます。

Excel VBAとSeleniumで無限スクロールから100件のデータを取得しExcelへ出力した結果

実務で使用する場合の注意点

実際のWebサイトでは、スクロールによってデータが追加される仕組みが異なる場合があります。

特に、以下の点に注意してください。

  • CSSセレクターを対象サイトに合わせて変更する
  • データの読み込み時間に合わせて待機時間を調整する
  • スクロール対象がページ全体ではなく特定の領域になっていないか確認する
  • 最大スクロール回数を設定して無限ループを防止する

また、データ件数が増えなくなった場合でも、すべてのデータを取得できたとは限りません。

実務では、取得予定件数との比較や読み込み完了を示す要素の確認なども組み合わせることをおすすめします。

Webスクレイピングを行う際は、対象サイトの利用規約なども確認するようにしてください。

最後に

いかがでしたでしょうか。

今回は、Excel VBAとSeleniumを使用して、無限スクロールのページからデータを取得する方法についてご紹介しました。

無限スクロールでは、最下部までスクロールするだけでなく、新しいデータが読み込まれたかどうかを確認することが重要となります。

今回紹介したように、スクロール前後のデータ件数を比較することで、新しいデータが追加されなくなるまで自動的に処理を繰り返すことができます。

実際に使用する場合は、対象サイトのHTML構造や読み込み速度に合わせて調整してください。

少しでも参考になれば幸いです。

開発依頼について

ココナラでWebスクレイピング開発サービスを出品しております。

自分で開発をしようと思ったけど、VBAでのネット記事が少なく困っている方も多いかと思います。

そんな方はいつでもお気軽にご相談ください。

また、本ブログからご依頼いただいた方については割引特典がございますので、

ご不明点と合わせてメッセージをいただけると幸いです。

業務の流れをまるごと自動化します Excel・Web・Teams・SaaSで業務全体を自動化

Webスクレイピング以外にもWebアプリの開発サービスも出品しております。

こちらについても、本ブログからご依頼いただいた方については割引特典がございますので、

お気軽にご相談ください。

スモールスケールのWebアプリ開発します 先ずはスモールスケールのWebアプリから始めませんか?

ご興味がある方はこちら!!

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA