0Pricing
Learn AI with Python · レッスン

大規模データセットのページングと収集

ページング、next_cursor パターン、time.sleep によるレート制限、プログレスバーを扱います。

「大規模データセットのページングと収集」はCoddyKit上の無料Learn AI with Pythonレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLearn AI with Python学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Learn AI with Pythonコースには全4レッスンが含まれています。

ページネーションが存在する理由

APIが何百万件ものレコードを1回のレスポンスで返すことは、ほとんどありません。各レスポンスを小さく高速に保つため、結果をページに分割します。

データセット全体を収集するには、すべてのページを順番に処理し、結果を結合する必要があります。このレッスンでは、一般的なページネーションの方式に加えて、レート制限と進捗の追跡について学びます。

ページ番号によるページネーション

最も単純な方式では、pageパラメータを使います。APIが空のページを返すまで、値を1つずつ増やします。

import requests

all_items = []
page = 1
while True:
    resp = requests.get(url, params={"page": page, "per_page": 100}, timeout=10)
    resp.raise_for_status()
    items = resp.json()
    if not items:
        break
    all_items.extend(items)
    page += 1
print(len(all_items), "items collected")

カーソル/次のURLによるページネーション

多くの最新のAPIは、次のページを指す次のURLまたはカーソルトークンを返します。次のリンクが存在する間、ループを続けます。

次のページの開始位置をサーバーが管理するため、この方式は堅牢です。

all_items = []
next_url = "https://api.example.com/items?limit=100"
while next_url:
    resp = requests.get(next_url, timeout=10)
    resp.raise_for_status()
    data = resp.json()
    all_items.extend(data["results"])
    next_url = data.get("next")   # None when no more pages
print(len(all_items))

time.sleepでレート制限を守る

APIには、1秒または1分あたりに送信できるリクエスト数の上限があります。過剰なリクエストを送ると、429 Too Many Requestsが返されたり、アクセスをブロックされたりします。

リクエストの間に短いtime.sleepを入れて、適切な速度を保ち、制限を超えないようにします。

import time

while next_url:
    resp = requests.get(next_url, timeout=10)
    resp.raise_for_status()
    data = resp.json()
    all_items.extend(data["results"])
    next_url = data.get("next")
    time.sleep(0.5)   # 2 requests per second

レート制限のヘッダーを読み取る

適切に設計されたAPIでは、X-RateLimit-RemainingやX-RateLimit-Resetのようなヘッダーで、残りの利用可能回数を通知します。

これらを読み取れば、常にスリープするのではなく、制限に近づいたときだけ処理を遅くできます。

remaining = int(resp.headers.get("X-RateLimit-Remaining", 1))
if remaining < 5:
    reset = int(resp.headers.get("X-RateLimit-Reset", 1))
    print("Near limit, sleeping", reset, "s")
    time.sleep(reset)

バックオフで429を処理する

429が返された場合、レスポンスに待機時間を示すRetry-Afterヘッダーが含まれていることがよくあります。再試行する前に、その指示に従って待機してください。

resp = requests.get(url, timeout=10)
if resp.status_code == 429:
    wait = int(resp.headers.get("Retry-After", 5))
    time.sleep(wait)
    resp = requests.get(url, timeout=10)   # retry once

tqdmで進捗バーを表示する

長時間かかる収集処理は、フィードバックがないと停止したように感じられます。tqdmは任意のイテラブルをラップし、処理速度と予測残り時間(ETA)を含む進捗バーをリアルタイムで表示します。

from tqdm import tqdm

for page in tqdm(range(1, 101), desc="Fetching"):
    resp = requests.get(url, params={"page": page}, timeout=10)
    all_items.extend(resp.json())
    time.sleep(0.2)

合計数が分からない場合のtqdm

カーソルによるページネーションでは、最初に全体の件数が分かりません。tqdmを手動カウンターとして使い、ループごとにupdate()を呼び出します。

from tqdm import tqdm

pbar = tqdm(desc="Pages")
while next_url:
    resp = requests.get(next_url, timeout=10)
    data = resp.json()
    all_items.extend(data["results"])
    next_url = data.get("next")
    pbar.update(1)
pbar.close()

増分方式で収集する

非常に大きなデータセットの場合、すべてをメモリ上に保持してはいけません。増分収集では、各ページを受信するたびにディスクへ書き込むため、処理がクラッシュしても進捗をすべて失わずに済みます。

import json

with open("items.jsonl", "w") as f:
    while next_url:
        resp = requests.get(next_url, timeout=10)
        data = resp.json()
        for item in data["results"]:
            f.write(json.dumps(item) + "\n")
        next_url = data.get("next")

再開可能な収集

最後に処理したカーソルまたはページ番号を保存しておくと、再実行時に最初からやり直さずに再開できます。これにより、長時間の処理でも障害に強くなります。

import os

start_page = 1
if os.path.exists("checkpoint.txt"):
    start_page = int(open("checkpoint.txt").read()) + 1

for page in range(start_page, 1000):
    # ... fetch and store ...
    open("checkpoint.txt", "w").write(str(page))

すべてを組み合わせる

実運用向けの収集ループでは、ページネーション、レート制限のためのスリープ、進捗表示、増分書き込み、チェックポイント保存をすべて組み合わせます。

from tqdm import tqdm
import time, json

with open("out.jsonl", "a") as f:
    next_url = "https://api.example.com/items?limit=100"
    pbar = tqdm(desc="Pages")
    while next_url:
        r = requests.get(next_url, timeout=10)
        r.raise_for_status()
        d = r.json()
        for it in d["results"]:
            f.write(json.dumps(it) + "\n")
        next_url = d.get("next")
        pbar.update(1)
        time.sleep(0.3)

クイックチェック:カーソルによるページネーション

あるAPIが、URLを示す"next"フィールドを返し、最後のページではNoneを返します。

まとめ:大規模なデータセットを収集する

これで、複数のページにまたがるデータセットを収集できるようになりました。

  • ページ番号とカーソル(while next_url)によるページネーション
  • time.sleepとレート制限のヘッダーで429を回避する
  • スロットリング発生時にRetry-Afterでバックオフする
  • 長時間の処理にtqdmの進捗バーを使う
  • 障害に備えて増分方式かつ再開可能な形で書き込む

次は、収集したデータを効率的に保存します。

よくある質問

「大規模データセットのページングと収集」レッスンは無料ですか?

はい。「大規模データセットのページングと収集」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Learn AI with Pythonコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Learn AI with Pythonコースには全4レッスンが含まれています。

「大規模データセットのページングと収集」で何を学びますか?

ページング、next_cursor パターン、time.sleep によるレート制限、プログレスバーを扱います。 ブラウザで直接実行するハンズオンコードでLearn AI with Pythonを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Learn AI with Pythonを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLearn AI with Pythonは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「大規模データセットのページングと収集」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLearn AI with Pythonレッスンでコードを書いて実行できますか?

はい。すべてのLearn AI with Pythonレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. データ収集のための REST API 基礎
  2. 大規模データセットのページングと収集
  3. 収集データを効率的に保存する
  4. 公開データ API の操作
← Learn AI with Pythonに戻る