feat: add pagination support for SPA and Ajax pagination

This commit is contained in:
Rohit
2025-03-17 16:03:14 +05:30
parent a047733e37
commit b172636eb1

View File

@@ -726,68 +726,100 @@ export default class Interpreter extends EventEmitter {
} }
let retryCount = 0; let retryCount = 0;
let navigationSuccess = false; let paginationSuccess = false;
while (retryCount < MAX_RETRIES && !navigationSuccess) { // Capture basic content signature before click
const captureContentSignature = async () => {
return await page.evaluate((selector) => {
const items = document.querySelectorAll(selector);
return {
url: window.location.href,
itemCount: items.length,
firstItems: Array.from(items).slice(0, 3).map(el => el.textContent || '').join('|')
};
}, config.listSelector);
};
const beforeSignature = await captureContentSignature();
debugLog(`Before click: ${beforeSignature.itemCount} items`);
while (retryCount < MAX_RETRIES && !paginationSuccess) {
try { try {
try { try {
await Promise.all([ await Promise.all([
page.waitForNavigation({ page.waitForNavigation({
waitUntil: 'networkidle', waitUntil: 'networkidle',
timeout: 15000 timeout: 15000
}).catch(e => {
throw e;
}), }),
button.click() button.click()
]); ]);
navigationSuccess = true; debugLog("Navigation successful after regular click");
} catch (error) { paginationSuccess = true;
debugLog(`Regular click failed on attempt ${retryCount + 1}. Trying DispatchEvent`); } catch (navError) {
debugLog("Regular click with navigation failed, trying dispatch event with navigation");
// If regular click fails, try dispatchEvent
if (page.url() === currentUrl) {
try { try {
await Promise.all([ await Promise.all([
page.waitForNavigation({ page.waitForNavigation({
waitUntil: 'networkidle', waitUntil: 'networkidle',
timeout: 15000 timeout: 15000
}).catch(e => {
throw e;
}), }),
button.dispatchEvent('click') button.dispatchEvent('click')
]); ]);
navigationSuccess = true; debugLog("Navigation successful after dispatch event");
} catch (dispatchError) { paginationSuccess = true;
debugLog(`DispatchEvent failed on attempt ${retryCount + 1}.`); } catch (dispatchNavError) {
try {
await button.click();
await page.waitForTimeout(2000);
} catch (clickError) {
await button.dispatchEvent('click');
await page.waitForTimeout(2000);
} }
} else {
navigationSuccess = true;
} }
} }
await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {});
if (!paginationSuccess) {
const newUrl = page.url(); const newUrl = page.url();
if (visitedUrls.has(newUrl)) { const afterSignature = await captureContentSignature();
debugLog(`Detected navigation to previously visited URL ${newUrl} on attempt ${retryCount + 1}`);
navigationSuccess = false;
}
if (navigationSuccess) { if (newUrl !== currentUrl) {
await page.waitForTimeout(1000); debugLog(`URL changed to ${newUrl}`);
visitedUrls.add(newUrl);
paginationSuccess = true;
}
else if (afterSignature.firstItems !== beforeSignature.firstItems) {
debugLog("Content changed without URL change");
paginationSuccess = true;
}
else if (afterSignature.itemCount !== beforeSignature.itemCount) {
debugLog(`Item count changed from ${beforeSignature.itemCount} to ${afterSignature.itemCount}`);
paginationSuccess = true;
}
} }
} catch (error) { } catch (error) {
debugLog(`Navigation attempt ${retryCount + 1} failed completely.`); debugLog(`Pagination attempt ${retryCount + 1} failed: ${error.message}`);
navigationSuccess = false;
} }
if (!navigationSuccess) { if (!paginationSuccess) {
retryCount++; retryCount++;
if (retryCount < MAX_RETRIES) { if (retryCount < MAX_RETRIES) {
debugLog(`Retrying navigation - attempt ${retryCount + 1} of ${MAX_RETRIES}`); debugLog(`Retrying pagination - attempt ${retryCount + 1} of ${MAX_RETRIES}`);
await page.waitForTimeout(RETRY_DELAY); await page.waitForTimeout(RETRY_DELAY);
} }
} }
} }
if (!navigationSuccess) { if (!paginationSuccess) {
debugLog(`Navigation failed after ${MAX_RETRIES} attempts`); debugLog(`Pagination failed after ${MAX_RETRIES} attempts`);
return allResults; return allResults;
} }
break; break;
} }