> ## Documentation Index
> Fetch the complete documentation index at: https://www.octoparse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Paginierung handhaben

> So gelangen Scraper über Seite eins hinaus: nummerierte Seiten, Weiter-Links, unendliches Scrollen, Mehr-laden-Schaltflächen, API-Offsets und Cursor.

Die Paginierung ist die Navigationsebene eines Scrapers. Nachdem er eine Seite abrufen, rendern und extrahieren kann, muss er eine praktische Frage beantworten: **Wo befindet sich der nächste Datensatzstapel und woran erkenne ich, dass es keinen weiteren gibt?**

Die meisten Paginierungsfehler entstehen, weil jede Website wie eine nummerierte Seitenliste behandelt wird. Tatsächlich kann ein Katalog URL-Parameter, eine Weiter-Schaltfläche, unendliches Scrollen, eine Mehr-laden-Schaltfläche, einen API-Offset oder ein undurchsichtiges Cursor-Token verwenden. Manche Websites kombinieren mehrere Muster.

## Mit der Anfrage beginnen, nicht mit der Benutzeroberfläche

Öffnen Sie vor dem Schreiben der Paginierungslogik die DevTools und beobachten Sie, was sich beim Wechsel zum nächsten Stapel ändert.

1. Öffnen Sie die Registerkarte „Network“ und filtern Sie nach Fetch/XHR.
2. Wählen Sie die nächste Seite aus, scrollen Sie nach unten oder klicken Sie auf „Mehr laden“.
3. Untersuchen Sie Anfrage-URL, Abfrageparameter, Anfrageinhalt und Antwort.
4. Entscheiden Sie, ob der Scraper Links folgen, mit der Seite interagieren oder einen API-Endpunkt direkt aufrufen sollte.

Nutzen Sie die Benutzeroberfläche als Hinweis, vertrauen Sie jedoch der Netzwerkanfrage. Eine „Mehr laden“-Schaltfläche könnte eine einfache API mit `offset=40` aufrufen. Ein Seitenlink könnte Ergebnisse nach der URL-Änderung tatsächlich per JavaScript laden.

| Was sich ändert                                                   | Was Sie zuerst versuchen sollten                                 |
| ----------------------------------------------------------------- | ---------------------------------------------------------------- |
| URL enthält `page=2`, `p=2` oder `/page/2`                        | Nummerierte URLs in einer Schleife durchlaufen                   |
| Ein `<a>`-Link verweist auf die nächste Seite                     | Dem `href` folgen, bis er verschwindet oder deaktiviert ist      |
| Inhalte erscheinen nach dem Scrollen                              | XHR-Anfrage ermitteln; nur bei Bedarf im Browser scrollen        |
| Inhalte erscheinen nach einem Klick                               | API-Anfrage wiederverwenden oder in einer Browsersitzung klicken |
| JSON enthält `next_cursor`, `endCursor`, `has_more` oder `offset` | Über die API-Antwort paginieren                                  |

## Nummerierte Seiten

Nummerierte Paginierung ist der einfachste Fall, weil der nächste Ort in der URL sichtbar ist:

```text theme={null}
https://example.com/products?page=1
https://example.com/products?page=2
https://example.com/catalog/page/3
```

Der Scraper kann die Seitennummer erhöhen und anhalten, wenn die Antwort keine Elemente, weniger Elemente als erwartet oder eine bekannte 404-/Leerzustandsseite enthält.

```python theme={null}
import requests
from bs4 import BeautifulSoup

all_products = []

for page in range(1, 100):
    html = requests.get(f"https://example.com/products?page={page}").text
    soup = BeautifulSoup(html, "html.parser")
    cards = soup.select(".product-card")

    if not cards:
        break

    for card in cards:
        all_products.append(card.select_one(".title").get_text(strip=True))
```

Achten Sie auf Seitenindizes, die bei `0` beginnen, Parameternamen wie `p` oder `start` und Websites, die bei einer ungültigen Seitennummer erneut Seite eins zurückgeben. Eine wiederholte erste Seite ist problematischer als eine leere, weil sie unbemerkt Duplikate erzeugen kann.

## Weiter-Links

Manche Websites zeigen keine Seitennummern, sondern nur einen „Weiter“-Link oder Pfeil. Handelt es sich um einen normalen Anker, behandeln Sie die Paginierung als Verfolgung von Links:

```python theme={null}
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

url = "https://example.com/products"
seen_urls = set()

while url and url not in seen_urls:
    seen_urls.add(url)
    soup = BeautifulSoup(requests.get(url).text, "html.parser")

    for card in soup.select(".product-card"):
        print(card.select_one(".title").get_text(strip=True))

    next_link = soup.select_one("a[rel='next'], a.next")
    url = urljoin(url, next_link["href"]) if next_link and next_link.get("href") else None
```

Die Absicherung mit `seen_urls` ist wichtig. Fehlerhaft konfigurierte Websites verweisen mit dem letzten „Weiter“-Link manchmal auf die aktuelle oder erste Seite. Prüfen Sie außerdem deaktivierte Zustände wie `aria-disabled="true"`, `disabled` oder eine `disabled`-Klasse, bevor Sie dem Link vertrauen.

## Unendliches Scrollen

Unendliches Scrollen wirkt wie ein reines Browserproblem, verwendet darunter aber meist eine API. Scrollen Sie bei geöffneten DevTools einmal und suchen Sie nach einer Anfrage, die den nächsten Datensatzstapel abruft. Relevante Parameter heißen häufig `offset`, `page`, `after`, `cursor` oder `limit`.

Ist der Endpunkt nutzbar, rufen Sie ihn direkt auf:

```python theme={null}
import requests

offset = 0
limit = 24
products = []

while True:
    data = requests.get(
        "https://example.com/api/products",
        params={"offset": offset, "limit": limit},
    ).json()

    batch = data.get("items", [])
    if not batch:
        break

    products.extend(batch)
    offset += len(batch)
```

Verwenden Sie einen Browser nur, wenn sich die API wegen Authentifizierung, signierter Parameter oder komplexem clientseitigem Zustand außerhalb der Seite nur schwer aufrufen lässt.

```python theme={null}
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://example.com/products")

    previous_count = 0
    for _ in range(40):
        page.mouse.wheel(0, 4000)
        page.wait_for_timeout(1500)

        current_count = page.locator(".product-card").count()
        if current_count == previous_count:
            break
        previous_count = current_count

    print(page.locator(".product-card").count())
    browser.close()
```

Verlassen Sie sich bei unendlichem Scrollen nicht nur auf die Seitenhöhe. Werbung, Bilder oder virtualisierte Listen können sie fortlaufend verändern. Elementanzahl, Netzwerkleerlauf und eine maximale Scrollzahl bilden eine sicherere Kombination.

## Mehr-laden-Schaltflächen

Eine Mehr-laden-Schaltfläche ist gesteuertes unendliches Scrollen. Die Seite wartet auf einen Klick, bevor sie den nächsten Stapel anfordert. Das erleichtert die Taktung, weil der Scraper warten, die neue Elementanzahl prüfen und eine fehlgeschlagene Anfrage wiederholen kann.

Ruft die Schaltfläche eine klar strukturierte API auf, verwenden Sie diese. Andernfalls klicken Sie in einer Browserschleife:

```python theme={null}
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://example.com/products")

    while page.locator("button.load-more").is_visible():
        before = page.locator(".product-card").count()
        page.locator("button.load-more").click()
        page.wait_for_function(
            "(count) => document.querySelectorAll('.product-card').length > count",
            before,
        )

    browser.close()
```

Die wichtige Prüfung lautet nicht nur „Schaltfläche angeklickt“, sondern „neue Datensätze erschienen“. Schaltflächen können still fehlschlagen, deaktiviert werden oder nach dem letzten Stapel sichtbar bleiben.

## Offset- und Cursor-APIs

Moderne Websites paginieren Daten häufig auf API-Ebene. Offset-Paginierung fragt eine numerische Position ab:

```text theme={null}
/api/products?offset=40&limit=20
```

Cursor-Paginierung fragt nach dem nächsten undurchsichtigen Token aus der vorherigen Antwort:

```json theme={null}
{
  "items": [],
  "pageInfo": {
    "hasNextPage": true,
    "endCursor": "eyJpZCI6MTAwfQ=="
  }
}
```

Cursor-Paginierung ist stabiler, wenn während des Scrapings Datensätze hinzukommen oder entfernt werden. Statt „die ersten 40 Zeilen überspringen“ bedeutet der Cursor „nach dieser bekannten Position fortfahren“.

```python theme={null}
import requests

cursor = None

while True:
    params = {"limit": 50}
    if cursor:
        params["after"] = cursor

    data = requests.get("https://example.com/api/products", params=params).json()
    for item in data.get("items", []):
        print(item["name"])

    page_info = data.get("pageInfo", {})
    if not page_info.get("hasNextPage"):
        break

    cursor = page_info.get("endCursor")
```

Behandeln Sie Ratenbegrenzungen bei API-Paginierung bewusst. Beachten Sie `Retry-After`, wiederholen Sie temporäre Fehler mit Backoff und speichern Sie den Fortschritt, wenn ein Neustart ab Seite eins bei großen Aufträgen teuer wäre.

## Hybride Paginierung

Echte Websites kombinieren häufig mehrere Muster:

* Eine Kategorie besitzt nummerierte Seiten, auf denen nach dem Scrollen jeweils weitere Produkte nachgeladen werden.
* Eine Suchseite beginnt mit „Mehr laden“ und wechselt dann zu nummerierten Links.
* Eine Oberfläche mit Registerkarten besitzt getrennte Paginierung für „Neu“, „Beliebt“ und „Sale“.
* Eine Listenseite paginiert Ergebnis-URLs; jede Detailseite besitzt wiederum eigene paginierte Rezensionen oder Kommentare.

Behandeln Sie dies als verschachtelte Schleifen. Die äußere Schleife ist für die größere Navigationseinheit zuständig, jede innere für eine wiederholte Aktion. Verfolgen Sie eindeutige IDs über den gesamten Lauf, damit keine Duplikate in die Ausgabe gelangen.

## Praktische Schutzmaßnahmen

* **Stoppsignal definieren.** Leere Ergebnismengen, fehlende Weiter-Links, deaktivierte Schaltflächen, `hasNextPage: false`, wiederholte Cursor und maximale Iterationszahlen sind gültige Stoppsignale.
* **Duplikate erkennen.** Unendliches Scrollen und Cursor-APIs können Datensätze wiederholen, wenn sich Daten während eines Laufs ändern. Speichern Sie stabile IDs oder kanonische URLs.
* **Navigation drosseln.** Fügen Sie zwischen Stapeln kleine zufällige Pausen ein. Browser-Automatisierung sollte auf Inhaltsänderungen warten, nicht nur auf feste Timeouts.
* **Fehler protokollieren.** Scheitert eine Seite nach mehreren Versuchen, speichern Sie URL oder Cursor und fahren Sie möglichst fort.
* **Legitime und stabile APIs bevorzugen.** Direkte API-Paginierung ist meist schneller und leichter zu validieren als Browsersteuerung.
* **Ein visuelles Tool verwenden, wenn Geschwindigkeit wichtiger als eigener Code ist.** In Octoparse lässt sich Paginierung für übliche Weiter-, Mehr-laden- und Infinite-Scroll-Abläufe visuell konfigurieren und anschließend lokal oder in der Cloud ausführen.

Paginierung bedeutet nicht nur „zur nächsten Seite gehen“. Sie ist die Steuerschleife des Scrapers. Mit eindeutiger Logik für den nächsten Schritt, einer zuverlässigen Stoppbedingung und Duplikatschutz kann der Scraper eine Website durchlaufen, ohne unbemerkt auf Seite eins anzuhalten oder endlos weiterzulaufen.
