Loading KAIROXO page正在加载 KAIROXO 页面Đang tải trang KAIROXO

KAIROXO
Tutorial

Pagination Scraping: Stop Rules and Record Deduplication

Recognize terminal pages, detect repeated cursors and reconcile unique records without mistaking safety limits for a complete collection.

KAIROXO

A person examining papers with a magnifying glass.

Pagination scraping fails quietly when the collector assumes that a page number, an empty response or a successful click means more than it does. A request can succeed and still return the previous page. A list can contain duplicates because new records arrived while the crawl was running. Reliable collection needs explicit continuation rules, stable record identities and a report of why traversal stopped.

Take an authorized public supplier catalog with twenty records per response. The operator needs every current supplier, not simply every page reachable within five minutes. Before building a loop, inspect how the site signals continuation and whether the list can change during collection. Those details determine what completeness can honestly mean.

Identify the navigation contract

Common patterns include numbered pages, a next link, an opaque cursor and a load-more action. The visible interface is only one clue. A background response may expose a next cursor or a has-more flag even when the browser shows a button. Document the observed request and response shape using a small sample of the first, middle and final pages.

Do not treat a cursor as an integer or construct a new one from its appearance. Opaque values can encode ordering, filters or snapshot state. Preserve them exactly. For link-based navigation, resolve relative URLs against the current page and verify the destination remains within the authorized scope before sending another request.

Implementation steps

  1. Choose an explicit stopping rule

    Prefer the site's documented end signal: no next link, a null cursor or a false continuation flag. An empty result may also be terminal, but only when that is the observed contract. Some services return temporarily empty batches with a continuation cursor. Conversely, a disabled button may still exist in the DOM and should not be clicked indefinitely.

    Always add a safety cap on pages and elapsed time. Reaching that cap means incomplete collection, not successful completion. Preserve the last cursor and stop reason so a later run can resume or investigate. A log saying only that the loop ended cannot distinguish a complete catalog from a job stopped by its own limit.

  2. Detect repeated navigation state

    Keep a set of processed cursor values or resolved page URLs. If the next value repeats, stop with a loop error. A server may ignore an expired cursor and return the first page; a page link can also point back to itself. Counting requests alone will not reveal this problem until a large safety cap is reached.

    Consider a page fingerprint when the navigation state advances but the returned record IDs do not. That is useful evidence, though a repeated set can occasionally be legitimate. Report it as a suspected navigation problem rather than silently discarding pages. Distinguish transport retries of one page from advances to another page in your metrics.

  3. Deduplicate records without losing observations

    Use the site's stable entity ID whenever available. Names and row positions are weak substitutes: two suppliers can share a name, and the same supplier can move between pages. Decide how to handle repeated IDs. A current-state dataset can keep the latest observation; an audit dataset may keep versions with observation times and collection identifiers.

    The small example makes its policy explicit: duplicate IDs replace earlier values, and only a null next cursor confirms completion. The injected page loader handles routing, authentication and retries separately. This separation lets tests simulate loops and overlapping pages without sending traffic to a real catalog.

    Codejavascript
    export async function collectPages(loadPage, { first = 'start', maxPages = 100 } = {}) {  const seenCursors = new Set(), records = new Map();  let cursor = first;  for (let page = 0; page < maxPages; page++) {    if (seenCursors.has(cursor)) throw new Error('pagination cursor repeated');    seenCursors.add(cursor);    const result = await loadPage(cursor);    if (!Array.isArray(result.items)) throw new Error('invalid page shape');    for (const item of result.items) {      if (typeof item.id !== 'string' || !item.id) throw new Error('missing stable ID');      records.set(item.id, item); // Deliberate policy: latest observation wins.    }    if (result.next === null) return { records: [...records.values()], pages: page + 1, complete: true };    if (typeof result.next !== 'string' || !result.next) throw new Error('missing or invalid next cursor; collection incomplete');    cursor = result.next;  }  throw new Error('page budget exhausted; collection incomplete');}
  4. Reconcile the completed collection

    Compare unique record count with a reliable total when the site exposes one. Keep in mind that a visible total may be approximate, filtered differently or changing during the crawl. Record the filters, sort order, region and time window with the count. A mismatch should trigger investigation, not an arbitrary change to the expected number.

    For moving lists, a stable sort with a tie-breaker or a server-provided snapshot can reduce gaps. Neither is always available. State that limitation when reporting completeness. A second pass with overlapping boundaries may reveal missed IDs, but it cannot prove a continuously changing source was captured at one perfectly consistent instant.

Keep session and access context stable

Language, cookies, filters and region can change the list that pagination traverses. Preserve the context required by the target across pages. If a proxy change invalidates a cursor or resets a session, start a deliberate recovery path rather than combining two differently filtered sequences into one apparently complete dataset.

KAIROXO supplies the configured access route; your collector still owns cursor handling and record reconciliation. See HTTPX concurrency guidance for separating bounded work from connection resources. Increasing parallelism does not automatically preserve the ordering assumptions of cursor-based navigation.

Frequently asked questions

Sources and further reading

Related KAIROXO guide

Loading KAIROXO page正在加载 KAIROXO 页面Đang tải trang KAIROXO