Короткий ответ
Пагинацию нужно проходить по курсору/токену, который возвращает само API (а не предполагать номера страниц "наугад"), а при получении 429 — приостанавливать запросы на время из заголовка Retry-After (если он есть) или по экспоненциальной задержке, и в любом случае ограничивать частоту запросов заранее, а не реагировать только постфактум.
Как это работает подробнее
большинство современных API для пагинации используют курсор (next_cursor, page_token) в ответе, который гарантированно работает даже если данные между запросами изменились; постраничная нумерация по номеру (?page=N) может "съедать" или дублировать записи при параллельных изменениях данных. Rate limiting на стороне сервера обычно сообщает лимиты через заголовки (X-RateLimit-Remaining, Retry-After), которые стоит использовать проактивно.
Пример кода
import time
import requests
def fetch_all_pages(base_url, headers):
cursor = None
all_items = []
while True:
params = {"cursor": cursor} if cursor else {}
response = requests.get(base_url, headers=headers, params=params, timeout=10)
if response.status_code == 429:
wait = int(response.headers.get("Retry-After", "5"))
print(f"Получен 429, ждём {wait}с перед повтором")
time.sleep(wait)
continue
response.raise_for_status()
payload = response.json()
all_items.extend(payload["items"])
cursor = payload.get("next_cursor")
if not cursor:
break
time.sleep(0.2) # базовый троттлинг между страницами
return all_itemsЧто использовать на практике
- Рекомендация. устойчивый скрипт выгрузки сочетает троттлинг "по расписанию" (например, не больше N запросов в секунду через
time.sleepмежду вызовами) с реактивной обработкой 429 через retry с уважениемRetry-After. Также важно делать выгрузку возобновляемой — сохранять последний обработанный курсор, чтобы при сбое на середине не начинать с нуля.
Подводные камни
- Ошибка. жёстко перебирать номера страниц инкрементом без использования
next_cursorиз ответа API; обрабатывать 429 как фатальную ошибку и останавливать весь скрипт вместо паузы и повтора; не сохранять прогресс выгрузки, из-за чего сбой на 950-й из 1000 страниц требует повторной выгрузки всего набора данных.