| 変化 | 最初に試すこと |
|---|---|
URLにpage=2や/page/2が出る | 番号付きURLをループする |
<a>のNextリンクがある | hrefを辿り、消える/無効になるまで続ける |
| スクロールで新しい項目が出る | XHR/APIを探し、必要ならブラウザでスクロールする |
| ボタンで項目が追加される | APIを再利用するか、ボタンをクリックする |
JSONにnext_cursor、has_more、offsetがある | APIレスポンスのページ情報で進める |
番号付きページ
もっとも単純な形式です。page=0から始まるサイト、pやstartなど別名のパラメータ、範囲外ページで1ページ目を返すサイトです。最後のケースは重複を生むため、URLだけでなく項目IDや商品URLも見て停止条件を作ります。
Nextリンク
番号がなく、Nextや矢印だけがあるサイトもあります。通常の<a>であればリンクを辿るだけです。最後のページでNextが消える場合もあれば、disabledやaria-disabled="true"になる場合もあります。要素の存在だけでなく無効状態を確認します。
URLの循環にも注意します。最後のNextが同じページや1ページ目を指すサイトでは、訪問済みURLの集合を持たないと無限ループになります。
無限スクロール
無限スクロールはブラウザ操作が必要に見えますが、多くの場合は裏側でAPIを呼んでいます。スクロール時にNetworkタブでoffset、cursor、after、pageなどを含むリクエストを探します。
APIが直接呼べるなら、ブラウザを動かすより高速で安定します。認証、署名付きパラメータ、複雑なクライアント状態がある場合だけ、PlaywrightやPuppeteerのようなブラウザ自動化でスクロールを再現します。停止条件はページ高さだけに頼らず、項目数、network idle、最大スクロール回数を組み合わせる方が安全です。
Load Moreボタン
Load Moreは制御された無限スクロールです。クリックごとに次のまとまりが追加されるため、スクロールよりもペースを調整しやすいのが利点です。 重要なのは「クリックできた」ではなく「新しい項目が増えた」ことを確認することです。ボタンは最後まで表示されたまま無効になることがあり、クリックが失敗してもエラーにならない場合があります。offsetとカーソルAPI
APIベースのページネーションには大きく2種類あります。offset方式は/api/products?offset=40&limit=20のように位置を数値で指定します。カーソル方式は前回レスポンスに含まれるendCursorやnext_cursorを次回リクエストに渡します。
動的なデータではカーソル方式の方が安定します。番号やoffsetは途中でデータが追加/削除されると重複や取りこぼしが起きますが、カーソルは「この位置の続き」を指すためです。
複合パターン
現実のサイトでは複数の方式が混ざります。- 番号付きページの各ページ内でさらに無限スクロールする
- 最初はLoad Moreで、途中から番号付きページになる
- New/Popular/Saleなどタブごとに独立したページネーションがある
- 一覧ページをページングし、詳細ページ内のレビューも別にページングする
実務上のガード
- 停止条件を必ず定義する
- 重複IDやURLを記録する
- 固定sleepだけでなく、項目数やDOM変化を待つ
- 失敗したURLやカーソルをログに残す
- APIが正当に使えるならブラウザ操作より優先する
- Octoparseのようなビジュアルツールでは、Nextページ、Load More、無限スクロールを設定し、ローカルまたはクラウドで実行できる