Prompt
How do I scrape paginated websites?
Latest observation
Scraping paginated websites usually means: fetch one page, find the “next page” link or page number, repeat until there are no more pages. The exact approach depends on how the site paginates.
1) First identify the pagination type
Common patterns:
A. URL-based pagination
Examples:
https://example.com/products?page=2https://example.com/articles?offset=20https://example.com/search/page/3
This is the easiest case: you just change the page number or offset in the request URL.
B. Link-based pagination
The page contains a “Next” button/link in the HTML:
<a href="/items?page=2">Next</a>
You fetch the page, parse the next link, and follow it until it disappears.
C. API-backed pagination
The page loads data from an endpoint returning JSON, often with:
pagelimitoffsetcursornext_cursor
This is often better to scrape than HTML, because it’s cleaner and more stable.
D. Infinite scroll / lazy load
The website loads more results as you scroll, usually via API requests. You can:
- inspect network requests in browser dev tools,
- find the underlying API,
- call it directly.
2) Basic scraping loop
Example: URL with ?page=
import requests
from bs4 import BeautifulSoup
base_url = "https://example.com/items"
page = 1
all_items = []
while True:
url = f"{base_url}?page={page}"
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
items = soup.select(".item")
if not items:
break
for item in items:
all_items.append(item.get_text(strip=True))
# stop if there is no next page
next_link = soup.select_one("a.next")
if not next_link:
break
page += 1
3) Following “Next” links
If the site provides a next-page URL in the HTML, use that instead of guessing page numbers:
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
url = "https://example.com/items"
all_items = []
while url:
r = requests.get(url, timeout=10)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
for item in soup.select(".item"):
all_items.append(item.get_text(strip=True))
next_a = soup.select_one("a[rel='next'], a.next")
url = urljoin(url, next_a["href"]) if next_a else None
This is more robust because it follows the site’s actual navigation.
4) Handling offset-based pagination
Sometimes the URL uses offsets rather than page numbers:
offset = 0
limit = 20
while True:
url = f"https://example.com/items?offset={offset}&limit={limit}"
r = requests.get(url)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
items = soup.select(".item")
if not items:
break
# process items...
offset += limit
5) Scraping API pagination
If you find an API endpoint returning JSON:
import requests
url = "https://example.com/api/items?page=1"
all_items = []
while url:
data = requests.get(url, timeout=10).json()
all_items.extend(data["results"])
url = data.get("next") # often a full URL or None
Or cursor-based pagination:
cursor = None
all_items = []
while True:
params = {}
if cursor:
params["cursor"] = cursor
data = requests.get("https://example.com/api/items", params=params).json()
all_items.extend(data["results"])
cursor = data.get("next_cursor")
if not cursor:
break
6) Avoid common issues
Rate limiting / blocking
- Add delays between requests:
import time
time.sleep(1)
- Use a proper
User-Agent - Keep request volume reasonable
- Respect robots.txt and the site’s terms
Duplicate or missing results
- Track item IDs/URLs to avoid duplicates
- Stop only when you truly hit the end, not just when a page is empty due to an error
JavaScript-rendered pages
If content is not in the HTML response, use:
- the site’s API directly, or
- a browser automation tool like Playwright or Selenium.
7) Practical strategy
When scraping paginated sites, do this:
- Open the page in your browser
- Check whether page changes are in the URL
- Inspect network requests for JSON APIs
- Prefer direct API scraping if available
- If not, parse HTML and follow the “next” link
- Add retries, delays, and deduplication
8) A simple reusable pattern
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import time
def scrape_paginated(start_url, item_selector, next_selector):
url = start_url
results = []
while url:
r = requests.get(url, timeout=10)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
results.extend([x.get_text(" ", strip=True) for x in soup.select(item_selector)])
next_link = soup.select_one(next_selector)
url = urljoin(url, next_link["href"]) if next_link and next_link.get("href") else None
time.sleep(1)
return results
If you want, I can show you how to scrape a specific paginated site using:
requests + BeautifulSoup,Scrapy,- or
Playwrightfor JavaScript-heavy pages.
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.