UNPKG

syphonx-core

Version:

SyphonX is a template-driven solution for extracting data from HTML in a highly efficient way. It combines the power of jQuery, Regular Expressions, and Javascript into a declarative template-driven format that extracts and reshapes HTML data into JSON.

78 lines 3.08 kB
import { sleep } from "./sleep.js"; export async function autoPaginate({ item_selector, next_button_selector, max_pages = 25, min_click_delay = 1000, max_click_delay, timeout = 30000 }) { let pages = 0; const from = $(item_selector).length; if (from === 0) return { from: 0, to: 0, pages, status: "no items found" }; if ($(next_button_selector).length === 0) return { from, to: from, pages, status: "next page button not found" }; if (max_click_delay === undefined) max_click_delay = min_click_delay; else if (max_click_delay < min_click_delay) max_click_delay = min_click_delay; const allItems = []; let status = "ok"; while (status === "ok" && max_pages-- > 0) { const currentItems = getCurrentItems(); allItems.push(...currentItems); let $next = $(next_button_selector); if ($next.length === 0) break; const itemsBeforeClick = getCurrentItems(); const t0 = Date.now(); while (Date.now() - t0 < timeout) { $next[0].scrollIntoView({ block: "center", behavior: "smooth" }); await sleep(500); $next[0].focus(); await sleep(100); $next[0].click(); const ok = await waitForPageLoad(itemsBeforeClick, 1000); if (ok) { status = "ok"; const interval = Math.random() * (max_click_delay - min_click_delay) + min_click_delay; await sleep(interval); break; } else { status = "timeout waiting for next page"; $next = $(next_button_selector); if ($next.length === 0) { status += ", next page button not found"; break; } } } pages += 1; } const $container = $(item_selector).parent(); $(item_selector).remove(); allItems.forEach(item => $container.append(item)); return { from, to: allItems.length, pages, status }; function getCurrentItems() { return $(item_selector).toArray().map(element => $(element)); } function itemsAreEqual(items1, items2) { if (items1.length !== items2.length) return false; for (let i = 0; i < items1.length; i++) if (!items1[i].is(items2[i])) return false; return true; } async function waitForPageLoad(previousItems, timeout = 1000) { const t0 = Date.now(); return new Promise(resolve => { const checkForNewContent = () => { const currentItems = getCurrentItems(); if (currentItems.length > 0 && !itemsAreEqual(currentItems, previousItems)) resolve(true); else if (Date.now() - t0 > timeout) resolve(false); else setTimeout(checkForNewContent, 100); }; checkForNewContent(); }); } } //# sourceMappingURL=autopaginate.js.map