mcp-scraper 0.86.5 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/README.md +17 -4
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-core.js +5 -5
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.js +5 -5
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-QJJQ4OAZ.js → chunk-2JVZQGSN.js} +50 -8
- package/dist/{chunk-NKRO2SUO.js → chunk-4QMUF6XM.js} +2 -2
- package/dist/{chunk-3JRZZVWL.js → chunk-ABF2CGOZ.js} +2 -2
- package/dist/{chunk-OWF2JJKN.js → chunk-GXBZXWXB.js} +8 -8
- package/dist/{chunk-KQWVJOVR.js → chunk-IHXAXYIS.js} +1 -1
- package/dist/{chunk-WFGAR4BZ.js → chunk-MZDNZQWT.js} +1 -1
- package/dist/{chunk-TV32LC76.js → chunk-P5FPC54B.js} +3 -3
- package/dist/{chunk-NH4QAH3X.js → chunk-S24LFPL7.js} +178 -53
- package/dist/{chunk-6IOGTFNS.js → chunk-UZPTGUDV.js} +1 -1
- package/dist/{chunk-BA6BPDSP.js → chunk-XIJI34RM.js} +1 -1
- package/dist/{extract-bundle-FALNLKYY.js → extract-bundle-565SBZCR.js} +2 -2
- package/dist/{gmail-service-BUSU4BVX.js → gmail-service-E6ALS7JG.js} +2 -2
- package/dist/index.cjs +185 -60
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +2 -2
- package/dist/{server-ARMF2IRI.js → server-PD3TDL6Q.js} +526 -428
- package/dist/{site-extract-repository-S5FYNFDY.js → site-extract-repository-VYFZASPU.js} +2 -2
- package/dist/{worker-OQSFSLNG.js → worker-LDCAULWL.js} +3 -3
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
RawPAAItemSchema,
|
|
16
16
|
postToMemoryLibrary,
|
|
17
17
|
recencyToTbs
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GXBZXWXB.js";
|
|
19
19
|
import {
|
|
20
20
|
CaptchaError,
|
|
21
21
|
ExtractionError,
|
|
@@ -134,6 +134,58 @@ var MapsSelectors = {
|
|
|
134
134
|
expandReview: '[data-review-id] button[aria-label*="See more"], [data-review-id] button.w8nwRe'
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
+
// src/driver/IBrowserDriver.ts
|
|
138
|
+
async function withManagedTemporaryPage(context, setup, operation, signal) {
|
|
139
|
+
let page;
|
|
140
|
+
let ended = false;
|
|
141
|
+
let timer;
|
|
142
|
+
let rejectStop = () => {
|
|
143
|
+
};
|
|
144
|
+
const aborted = () => signal?.reason instanceof DOMException && signal.reason.name === "TimeoutError" ? signal.reason : new RequestAbortedError();
|
|
145
|
+
const onAbort = () => rejectStop(aborted());
|
|
146
|
+
const stop = new Promise((_, reject) => {
|
|
147
|
+
rejectStop = reject;
|
|
148
|
+
});
|
|
149
|
+
const close = async (target) => {
|
|
150
|
+
let closeTimer;
|
|
151
|
+
try {
|
|
152
|
+
await Promise.race([
|
|
153
|
+
target.close().catch(() => {
|
|
154
|
+
}),
|
|
155
|
+
new Promise((resolve) => {
|
|
156
|
+
closeTimer = setTimeout(resolve, 2e3);
|
|
157
|
+
})
|
|
158
|
+
]);
|
|
159
|
+
} finally {
|
|
160
|
+
if (closeTimer) clearTimeout(closeTimer);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
if (signal?.aborted) throw aborted();
|
|
164
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
165
|
+
timer = setTimeout(() => rejectStop(new DOMException("Optional pagination timed out", "TimeoutError")), 3e4);
|
|
166
|
+
try {
|
|
167
|
+
return await Promise.race([
|
|
168
|
+
(async () => {
|
|
169
|
+
const created = await context.newPage();
|
|
170
|
+
if (ended) {
|
|
171
|
+
await close(created);
|
|
172
|
+
throw new RequestAbortedError();
|
|
173
|
+
}
|
|
174
|
+
page = created;
|
|
175
|
+
await setup(created);
|
|
176
|
+
if (ended) throw new RequestAbortedError();
|
|
177
|
+
return operation(created);
|
|
178
|
+
})(),
|
|
179
|
+
stop
|
|
180
|
+
]);
|
|
181
|
+
} finally {
|
|
182
|
+
ended = true;
|
|
183
|
+
if (timer) clearTimeout(timer);
|
|
184
|
+
signal?.removeEventListener("abort", onAbort);
|
|
185
|
+
if (page) await close(page);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
137
189
|
// src/lib/browser-user-agent.ts
|
|
138
190
|
var RUNTIME_BROWSER_UA = /\b(?:HeadlessChrome|Chrome|Chromium|Firefox)\/\d+|\bVersion\/\d+.*\bSafari\//;
|
|
139
191
|
async function detectPageUserAgent(page) {
|
|
@@ -523,6 +575,11 @@ var BrowserDriver = class {
|
|
|
523
575
|
};
|
|
524
576
|
});
|
|
525
577
|
}
|
|
578
|
+
async withTemporaryPage(operation, signal) {
|
|
579
|
+
if (!this.context) throw new Error("Browser context is not available");
|
|
580
|
+
return withManagedTemporaryPage(this.context, async () => {
|
|
581
|
+
}, operation, signal);
|
|
582
|
+
}
|
|
526
583
|
async navigateToSERP(query, uule, gl, hl, options) {
|
|
527
584
|
const params = new URLSearchParams({ q: query, gl, hl, pws: "0" });
|
|
528
585
|
if (options?.tbs) params.set("tbs", options.tbs);
|
|
@@ -927,7 +984,10 @@ var BrightDataSerpDriver = class {
|
|
|
927
984
|
const customCdp = this.cdpSession;
|
|
928
985
|
const sessionResponse = await customCdp.send("Browser.getSessionId");
|
|
929
986
|
this.providerSessionId = validateProviderSessionId(sessionResponse?.sessionId);
|
|
930
|
-
await this.page
|
|
987
|
+
await this.setupPage(this.page);
|
|
988
|
+
}
|
|
989
|
+
async setupPage(page) {
|
|
990
|
+
await page.route("**/*", async (route) => {
|
|
931
991
|
const request = route.request();
|
|
932
992
|
const resourceType = request.resourceType();
|
|
933
993
|
let requestUrl;
|
|
@@ -952,6 +1012,10 @@ var BrightDataSerpDriver = class {
|
|
|
952
1012
|
await route.continue();
|
|
953
1013
|
});
|
|
954
1014
|
}
|
|
1015
|
+
async withTemporaryPage(operation, signal) {
|
|
1016
|
+
if (!this.context || this.closing) throw new Error("Browser context is not available");
|
|
1017
|
+
return withManagedTemporaryPage(this.context, (page) => this.setupPage(page), operation, signal);
|
|
1018
|
+
}
|
|
955
1019
|
async navigateToSERP(query, uule, gl, hl, options) {
|
|
956
1020
|
if (!this.page) throw new Error("Browser page is not available");
|
|
957
1021
|
const params = new URLSearchParams({ q: query, gl, hl, pws: "0" });
|
|
@@ -1927,6 +1991,11 @@ function parsedGoogleGoto(value) {
|
|
|
1927
1991
|
if (!url || url.protocol !== "https:" || !isGoogleHost(url.hostname) || url.pathname !== "/goto") return null;
|
|
1928
1992
|
return url.searchParams.get("url") ? url : null;
|
|
1929
1993
|
}
|
|
1994
|
+
function hasResolvedGotoDestination(value) {
|
|
1995
|
+
if (value.linkType !== "google_goto_redirect" || value.resolutionStatus !== "resolved" || !parsedGoogleGoto(value.rawUrl) || !value.resolvedUrl) return false;
|
|
1996
|
+
const destination = safeHttpUrl(value.resolvedUrl);
|
|
1997
|
+
return Boolean(destination && !isGoogleHost(destination.hostname) && destination.href === value.resolvedUrl && value.url === destination.href);
|
|
1998
|
+
}
|
|
1930
1999
|
function questionIdFor(question) {
|
|
1931
2000
|
const normalized = question.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\p{L}\p{N}\s]/gu, "").replace(/\s+/g, " ").trim();
|
|
1932
2001
|
return `paa_${createHash("sha256").update(normalized).digest("hex").slice(0, 16)}`;
|
|
@@ -2143,8 +2212,12 @@ async function resolveHarvestResultGoogleGotoLinks(result, options = {}) {
|
|
|
2143
2212
|
}
|
|
2144
2213
|
async function resolveGoogleOutboundLinks(page, values, options = {}) {
|
|
2145
2214
|
const byRawUrl = /* @__PURE__ */ new Map();
|
|
2146
|
-
for (const value of values)
|
|
2147
|
-
|
|
2215
|
+
for (const value of values) {
|
|
2216
|
+
const existing = byRawUrl.get(value.rawUrl);
|
|
2217
|
+
if (existing && hasResolvedGotoDestination(existing)) continue;
|
|
2218
|
+
byRawUrl.set(value.rawUrl, value.linkType === "google_goto_redirect" && !hasResolvedGotoDestination(value) ? { ...value, url: value.rawUrl, resolvedUrl: null, resolutionStatus: "unresolved" } : value);
|
|
2219
|
+
}
|
|
2220
|
+
const inputs = [...byRawUrl.values()].filter((value) => value.linkType === "google_goto_redirect" && !hasResolvedGotoDestination(value));
|
|
2148
2221
|
if (inputs.length === 0) return byRawUrl;
|
|
2149
2222
|
const deadlineMs = Date.now() + (options.totalBudgetMs ?? DEFAULT_TOTAL_BUDGET_MS);
|
|
2150
2223
|
const direct = await resolveGoogleGotoUrls(inputs.map((value) => value.rawUrl), options);
|
|
@@ -2360,7 +2433,7 @@ var PAAExtractor = class {
|
|
|
2360
2433
|
];
|
|
2361
2434
|
const unique = new Map(candidates.map((link) => [link.rawUrl, link]));
|
|
2362
2435
|
let resolverNonGoogleRequestsObserved = 0;
|
|
2363
|
-
const resolved = await resolveGoogleOutboundLinks(page,
|
|
2436
|
+
const resolved = await resolveGoogleOutboundLinks(page, candidates, {
|
|
2364
2437
|
onNetworkAudit: (audit) => {
|
|
2365
2438
|
resolverNonGoogleRequestsObserved = audit.nonGoogleRequestsObserved;
|
|
2366
2439
|
}
|
|
@@ -2611,6 +2684,7 @@ var PAAExtractor = class {
|
|
|
2611
2684
|
diagnostics: {
|
|
2612
2685
|
completionStatus: "paa_found",
|
|
2613
2686
|
problem: null,
|
|
2687
|
+
...material?.pagination ? { pagination: { ...material.pagination } } : {},
|
|
2614
2688
|
resultQuality: "partial",
|
|
2615
2689
|
degradedResult: false,
|
|
2616
2690
|
retryRecommended: true,
|
|
@@ -3575,6 +3649,55 @@ var PAAExtractor = class {
|
|
|
3575
3649
|
...locationEvidence ? { locationEvidence } : {}
|
|
3576
3650
|
};
|
|
3577
3651
|
}
|
|
3652
|
+
async captureSecondOrganicPage(page, options, signal) {
|
|
3653
|
+
this.throwIfAborted(signal);
|
|
3654
|
+
if (!this.driver.withTemporaryPage) return { organic: [], status: "failed", failureCode: "unsupported_driver" };
|
|
3655
|
+
let guardedFailure;
|
|
3656
|
+
try {
|
|
3657
|
+
const initial = new URL(page.url());
|
|
3658
|
+
const valid = (raw) => {
|
|
3659
|
+
try {
|
|
3660
|
+
const url = new URL(raw, initial);
|
|
3661
|
+
return initial.origin === "https://www.google.com" && url.origin === initial.origin && !url.username && !url.password && url.pathname === "/search" && url.searchParams.getAll("q").length === 1 && url.searchParams.get("q") === options.query && url.searchParams.getAll("start").length === 1 && url.searchParams.get("start") === "10" && (!url.searchParams.has("num") || url.searchParams.get("num") === "10") && ["gl", "hl"].every((key) => !url.searchParams.has(key) || url.searchParams.getAll(key).length === 1 && url.searchParams.get(key) === options[key]) && ["uule", "tbs", "udm", "tbm", "pws"].every((key) => url.searchParams.getAll(key).length <= 1 && url.searchParams.get(key) === initial.searchParams.get(key));
|
|
3662
|
+
} catch {
|
|
3663
|
+
return false;
|
|
3664
|
+
}
|
|
3665
|
+
};
|
|
3666
|
+
const href = await page.evaluate(() => {
|
|
3667
|
+
const next = document.querySelector('a#pnnext, a[rel="next"]');
|
|
3668
|
+
return next?.getAttribute("href") ?? null;
|
|
3669
|
+
});
|
|
3670
|
+
if (!href) return { organic: [], status: "unavailable", failureCode: "missing_next" };
|
|
3671
|
+
if (!valid(href)) return { organic: [], status: "unavailable", failureCode: "invalid_next" };
|
|
3672
|
+
const organic = await this.driver.withTemporaryPage(async (second) => {
|
|
3673
|
+
await second.route("**/*", async (route) => {
|
|
3674
|
+
const request = route.request();
|
|
3675
|
+
if (request.isNavigationRequest() && request.frame() === second.mainFrame() && !valid(request.url())) {
|
|
3676
|
+
guardedFailure = /^https:\/\/www\.google\.com\/sorry(?:\/|\?)/.test(request.url()) ? "captcha" : "invalid_next";
|
|
3677
|
+
await route.abort("blockedbyclient");
|
|
3678
|
+
} else await route.fallback();
|
|
3679
|
+
});
|
|
3680
|
+
await second.goto(new URL(href, initial).href, { waitUntil: "domcontentloaded", timeout: 2e4 });
|
|
3681
|
+
this.throwIfAborted(signal);
|
|
3682
|
+
await this.throwIfCaptcha(second, "Google SERP page 2");
|
|
3683
|
+
if (!valid(second.url())) {
|
|
3684
|
+
guardedFailure = "invalid_next";
|
|
3685
|
+
throw new Error("Invalid pagination landing");
|
|
3686
|
+
}
|
|
3687
|
+
return this.extractOrganicResults(second);
|
|
3688
|
+
}, signal);
|
|
3689
|
+
this.throwIfAborted(signal);
|
|
3690
|
+
return organic.length > 0 ? { organic: organic.map((row) => ({ ...row, position: row.position + 10 })), status: "captured" } : { organic: [], status: "unavailable", failureCode: "empty_page" };
|
|
3691
|
+
} catch (err) {
|
|
3692
|
+
this.throwIfAborted(signal);
|
|
3693
|
+
if (err instanceof RequestAbortedError) throw err;
|
|
3694
|
+
return {
|
|
3695
|
+
organic: [],
|
|
3696
|
+
status: "failed",
|
|
3697
|
+
failureCode: guardedFailure ?? (err instanceof CaptchaError ? "captcha" : err instanceof Error && (err.name === "TimeoutError" || /timed? ?out/i.test(err.message)) ? "timeout" : "navigation_error")
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3578
3701
|
async extract(options, signal) {
|
|
3579
3702
|
const startMs = Date.now();
|
|
3580
3703
|
this.completeness = { paaWithoutAnswer: 0, paaWithoutSource: 0, paaAnswersRecovered: 0, aioShareCaptured: null };
|
|
@@ -3778,23 +3901,49 @@ var PAAExtractor = class {
|
|
|
3778
3901
|
const initialLocationEvidence = options.debug ? inferSerpLocationEvidence(canonicalLocation, organicResults, localPack) : void 0;
|
|
3779
3902
|
this.reporter.onVideos(videos);
|
|
3780
3903
|
this.reporter.onForums(forums);
|
|
3904
|
+
const aiSurfaces = includeAiOverview ? await this.extractAISurfaces(page, options) : emptyAiSurfaces;
|
|
3905
|
+
let pagination = {
|
|
3906
|
+
requestedPages: (options.pages ?? 1) >= 2 ? 2 : 1,
|
|
3907
|
+
capturedPages: 1,
|
|
3908
|
+
page2Status: (options.pages ?? 1) >= 2 ? "not_attempted" : "not_requested",
|
|
3909
|
+
page1OrganicCount: organicResults.length,
|
|
3910
|
+
page2OrganicCount: 0
|
|
3911
|
+
};
|
|
3912
|
+
let allOrganic = organicResults;
|
|
3913
|
+
this.checkpointMaterial = {
|
|
3914
|
+
surface: aiSurfaces.surface,
|
|
3915
|
+
aiOverview: aiSurfaces.aiOverview,
|
|
3916
|
+
aiMode: aiSurfaces.aiMode,
|
|
3917
|
+
whatPeopleSaying,
|
|
3918
|
+
videos,
|
|
3919
|
+
forums,
|
|
3920
|
+
organicResults: allOrganic,
|
|
3921
|
+
localPack,
|
|
3922
|
+
entityIds,
|
|
3923
|
+
pagination
|
|
3924
|
+
};
|
|
3925
|
+
await this.emitProgress("serp_captured");
|
|
3926
|
+
if (pagination.requestedPages === 2) {
|
|
3927
|
+
const second = await this.captureSecondOrganicPage(page, executionOptions, signal);
|
|
3928
|
+
allOrganic = [...organicResults, ...second.organic];
|
|
3929
|
+
pagination = {
|
|
3930
|
+
...pagination,
|
|
3931
|
+
capturedPages: second.status === "captured" ? 2 : 1,
|
|
3932
|
+
page2Status: second.status,
|
|
3933
|
+
page2OrganicCount: second.organic.length,
|
|
3934
|
+
...second.failureCode ? { failureCode: second.failureCode } : {}
|
|
3935
|
+
};
|
|
3936
|
+
this.checkpointMaterial = { ...this.checkpointMaterial, organicResults: allOrganic, pagination };
|
|
3937
|
+
await this.emitProgress("serp_captured");
|
|
3938
|
+
await this.resolveMaterialLinks(page, [], allOrganic, aiSurfaces.aiOverview, aiSurfaces.aiMode);
|
|
3939
|
+
this.checkpointMaterial = { ...this.checkpointMaterial, organicResults: allOrganic };
|
|
3940
|
+
await this.emitProgress("serp_captured");
|
|
3941
|
+
}
|
|
3942
|
+
const locationEvidence = options.debug ? inferSerpLocationEvidence(canonicalLocation, allOrganic, localPack) : initialLocationEvidence;
|
|
3781
3943
|
if (!hasPaa) {
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
const p2params = new URLSearchParams({ q: executionOptions.query, gl: options.gl, hl: options.hl, pws: "0", start: "10" });
|
|
3786
|
-
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
3787
|
-
if (uule) p2params.set("uule", uule);
|
|
3788
|
-
await this.driver.navigateTo("https://www.google.com/search?" + p2params.toString());
|
|
3789
|
-
await this.throwIfCaptcha(page, "Google SERP page 2");
|
|
3790
|
-
const p2organic = await this.extractOrganicResults(page);
|
|
3791
|
-
noPaaOrganic = [...organicResults, ...p2organic.map((r) => ({ ...r, position: r.position + 10 }))];
|
|
3792
|
-
if (options.debug) {
|
|
3793
|
-
locationEvidence2 = inferSerpLocationEvidence(canonicalLocation, noPaaOrganic, localPack);
|
|
3794
|
-
}
|
|
3795
|
-
}
|
|
3796
|
-
const aiSurfaces2 = includeAiOverview ? await this.extractAISurfaces(page, options) : emptyAiSurfaces;
|
|
3797
|
-
await this.resolveMaterialLinks(page, [], noPaaOrganic, aiSurfaces2.aiOverview, aiSurfaces2.aiMode);
|
|
3944
|
+
await this.resolveMaterialLinks(page, [], allOrganic, aiSurfaces.aiOverview, aiSurfaces.aiMode);
|
|
3945
|
+
this.checkpointMaterial = { ...this.checkpointMaterial, organicResults: allOrganic };
|
|
3946
|
+
await this.emitProgress("serp_captured");
|
|
3798
3947
|
const stats2 = {
|
|
3799
3948
|
seed: executionOptions.query,
|
|
3800
3949
|
totalQuestions: 0,
|
|
@@ -3811,39 +3960,27 @@ var PAAExtractor = class {
|
|
|
3811
3960
|
completionStatus: "no_paa",
|
|
3812
3961
|
noPaaObserved: true,
|
|
3813
3962
|
problem: null,
|
|
3963
|
+
pagination,
|
|
3814
3964
|
paaLifecycle: { ...this.paaLifecycle },
|
|
3815
3965
|
completeness: { ...this.completeness },
|
|
3816
3966
|
links: { ...this.linkDiagnostics },
|
|
3817
|
-
...options.debug ? { debug: this.buildHarvestDebugSnapshot(executionOptions, canonicalLocation, uule,
|
|
3967
|
+
...options.debug ? { debug: this.buildHarvestDebugSnapshot(executionOptions, canonicalLocation, uule, locationEvidence, locationResolution) } : {}
|
|
3818
3968
|
},
|
|
3819
3969
|
totalQuestions: 0,
|
|
3820
|
-
surface:
|
|
3821
|
-
aiOverview:
|
|
3822
|
-
aiMode:
|
|
3970
|
+
surface: aiSurfaces.surface,
|
|
3971
|
+
aiOverview: aiSurfaces.aiOverview,
|
|
3972
|
+
aiMode: aiSurfaces.aiMode,
|
|
3823
3973
|
whatPeopleSaying,
|
|
3824
3974
|
tree: [],
|
|
3825
3975
|
flat: [],
|
|
3826
3976
|
videos,
|
|
3827
3977
|
forums,
|
|
3828
|
-
organicResults:
|
|
3978
|
+
organicResults: allOrganic,
|
|
3829
3979
|
localPack,
|
|
3830
3980
|
entityIds,
|
|
3831
3981
|
stats: stats2
|
|
3832
3982
|
};
|
|
3833
3983
|
}
|
|
3834
|
-
const aiSurfaces = includeAiOverview ? await this.extractAISurfaces(page, options) : emptyAiSurfaces;
|
|
3835
|
-
this.checkpointMaterial = {
|
|
3836
|
-
surface: aiSurfaces.surface,
|
|
3837
|
-
aiOverview: aiSurfaces.aiOverview,
|
|
3838
|
-
aiMode: aiSurfaces.aiMode,
|
|
3839
|
-
whatPeopleSaying,
|
|
3840
|
-
videos,
|
|
3841
|
-
forums,
|
|
3842
|
-
organicResults,
|
|
3843
|
-
localPack,
|
|
3844
|
-
entityIds
|
|
3845
|
-
};
|
|
3846
|
-
await this.emitProgress("serp_captured");
|
|
3847
3984
|
const flat = await this.runBFS(page, executionOptions, signal);
|
|
3848
3985
|
this.throwIfAborted(signal);
|
|
3849
3986
|
const shortVidsParams = new URLSearchParams({ q: executionOptions.query, gl: options.gl, hl: options.hl, pws: "0", udm: ShortVideoSelectors.udm });
|
|
@@ -3864,20 +4001,6 @@ var PAAExtractor = class {
|
|
|
3864
4001
|
}
|
|
3865
4002
|
}
|
|
3866
4003
|
this.reporter.onVideos(shortVideos);
|
|
3867
|
-
let allOrganic = organicResults;
|
|
3868
|
-
let locationEvidence = initialLocationEvidence;
|
|
3869
|
-
if ((options.pages ?? 1) >= 2) {
|
|
3870
|
-
const p2params = new URLSearchParams({ q: executionOptions.query, gl: options.gl, hl: options.hl, pws: "0", start: "10" });
|
|
3871
|
-
if (recencyToTbs(options.recency)) p2params.set("tbs", recencyToTbs(options.recency));
|
|
3872
|
-
if (uule) p2params.set("uule", uule);
|
|
3873
|
-
await this.driver.navigateTo("https://www.google.com/search?" + p2params.toString());
|
|
3874
|
-
await this.throwIfCaptcha(page, "Google SERP page 2");
|
|
3875
|
-
const p2organic = await this.extractOrganicResults(page);
|
|
3876
|
-
allOrganic = [...organicResults, ...p2organic.map((r) => ({ ...r, position: r.position + 10 }))];
|
|
3877
|
-
if (options.debug) {
|
|
3878
|
-
locationEvidence = inferSerpLocationEvidence(canonicalLocation, allOrganic, localPack);
|
|
3879
|
-
}
|
|
3880
|
-
}
|
|
3881
4004
|
await this.resolveMaterialLinks(page, flat, allOrganic, aiSurfaces.aiOverview, aiSurfaces.aiMode);
|
|
3882
4005
|
this.checkpointMaterial = {
|
|
3883
4006
|
...this.checkpointMaterial,
|
|
@@ -3887,6 +4010,7 @@ var PAAExtractor = class {
|
|
|
3887
4010
|
videos: [...videos, ...shortVideos],
|
|
3888
4011
|
organicResults: allOrganic
|
|
3889
4012
|
};
|
|
4013
|
+
await this.emitProgress("expansion_finished");
|
|
3890
4014
|
const allVideos = [...videos, ...shortVideos];
|
|
3891
4015
|
const tree = this.buildTree(flat, executionOptions.query);
|
|
3892
4016
|
const stats = {
|
|
@@ -3904,6 +4028,7 @@ var PAAExtractor = class {
|
|
|
3904
4028
|
diagnostics: {
|
|
3905
4029
|
completionStatus: "paa_found",
|
|
3906
4030
|
problem: null,
|
|
4031
|
+
pagination,
|
|
3907
4032
|
paaLifecycle: { ...this.paaLifecycle },
|
|
3908
4033
|
completeness: { ...this.completeness },
|
|
3909
4034
|
links: { ...this.linkDiagnostics },
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
createSiteExtractContentReader,
|
|
11
11
|
createSiteExtractImageArtifact,
|
|
12
12
|
extractJobLimitInfo
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IHXAXYIS.js";
|
|
14
14
|
import "./chunk-OZJMVCDK.js";
|
|
15
15
|
import {
|
|
16
16
|
computeIssues,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
renderLinkReport
|
|
20
20
|
} from "./chunk-PGJQDMC2.js";
|
|
21
21
|
import "./chunk-DNM65UCK.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-4QMUF6XM.js";
|
|
23
23
|
import "./chunk-GGZEC22A.js";
|
|
24
24
|
import {
|
|
25
25
|
getDb
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
GmailServiceError,
|
|
8
8
|
normalizeGmailMessage,
|
|
9
9
|
parseGmailAddresses
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MZDNZQWT.js";
|
|
11
11
|
import "./chunk-C5Z4OFKW.js";
|
|
12
12
|
import "./chunk-T3MZISOF.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-4QMUF6XM.js";
|
|
14
14
|
import "./chunk-OPQIGAFB.js";
|
|
15
15
|
import "./chunk-YXNDOQXN.js";
|
|
16
16
|
export {
|