mcp-scraper 0.3.28 → 0.3.40
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/dist/bin/api-server.cjs +2459 -1137
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +237 -6
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/bin/paa-harvest.cjs +109 -5
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-TRNSXR46.js → chunk-DVRPXPYH.js} +22 -3
- package/dist/chunk-DVRPXPYH.js.map +1 -0
- package/dist/{chunk-QSSH4RCX.js → chunk-GMTS35L6.js} +111 -7
- package/dist/chunk-GMTS35L6.js.map +1 -0
- package/dist/chunk-I5EFBTYE.js +7 -0
- package/dist/chunk-I5EFBTYE.js.map +1 -0
- package/dist/{chunk-H74L743B.js → chunk-KJWNVQFL.js} +39 -2
- package/dist/chunk-KJWNVQFL.js.map +1 -0
- package/dist/{chunk-NGD4ITAO.js → chunk-QLQYNE7E.js} +238 -7
- package/dist/chunk-QLQYNE7E.js.map +1 -0
- package/dist/{db-FP2ABUU4.js → db-LYQENFPW.js} +2 -2
- package/dist/index.cjs +109 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +2 -2
- package/dist/{server-IDDX7KGT.js → server-HB7WJO3N.js} +1154 -251
- package/dist/server-HB7WJO3N.js.map +1 -0
- package/dist/{worker-NV4GTIRG.js → worker-TL4J65DE.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-7MY2NSQX.js +0 -7
- package/dist/chunk-7MY2NSQX.js.map +0 -1
- package/dist/chunk-H74L743B.js.map +0 -1
- package/dist/chunk-NGD4ITAO.js.map +0 -1
- package/dist/chunk-QSSH4RCX.js.map +0 -1
- package/dist/chunk-TRNSXR46.js.map +0 -1
- package/dist/server-IDDX7KGT.js.map +0 -1
- /package/dist/{db-FP2ABUU4.js.map → db-LYQENFPW.js.map} +0 -0
- /package/dist/{worker-NV4GTIRG.js.map → worker-TL4J65DE.js.map} +0 -0
|
@@ -97,7 +97,7 @@ import {
|
|
|
97
97
|
stripeEventAlreadyProcessed,
|
|
98
98
|
updateKpoJobState,
|
|
99
99
|
verifyPassword
|
|
100
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-DVRPXPYH.js";
|
|
101
101
|
export {
|
|
102
102
|
CREDIT_LOT_TTL,
|
|
103
103
|
SiteAuditJobRowSchema,
|
|
@@ -198,4 +198,4 @@ export {
|
|
|
198
198
|
updateKpoJobState,
|
|
199
199
|
verifyPassword
|
|
200
200
|
};
|
|
201
|
-
//# sourceMappingURL=db-
|
|
201
|
+
//# sourceMappingURL=db-LYQENFPW.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -1597,6 +1597,13 @@ var PAAExtractor = class {
|
|
|
1597
1597
|
}
|
|
1598
1598
|
driver;
|
|
1599
1599
|
reporter;
|
|
1600
|
+
completeness = {
|
|
1601
|
+
paaWithoutAnswer: 0,
|
|
1602
|
+
paaWithoutSource: 0,
|
|
1603
|
+
paaAnswersRecovered: 0,
|
|
1604
|
+
aioShareCaptured: null
|
|
1605
|
+
};
|
|
1606
|
+
aioShareUrlEarly = null;
|
|
1600
1607
|
normalizeQuestion(q) {
|
|
1601
1608
|
return q.toLowerCase().replace(/[^\w\s]/g, "").replace(/\s+/g, " ").trim();
|
|
1602
1609
|
}
|
|
@@ -1725,6 +1732,7 @@ var PAAExtractor = class {
|
|
|
1725
1732
|
}
|
|
1726
1733
|
}
|
|
1727
1734
|
const itemMap = new Map((await this.extractVisibleItems(page)).map((i) => [i.question, i]));
|
|
1735
|
+
await this.fillIncompleteItems(page, orderedQs, itemMap, options);
|
|
1728
1736
|
for (const q of orderedQs) {
|
|
1729
1737
|
if (results.length >= options.maxQuestions) break;
|
|
1730
1738
|
const key = this.normalizeQuestion(q);
|
|
@@ -1738,8 +1746,52 @@ var PAAExtractor = class {
|
|
|
1738
1746
|
results.push(this.toFlatRow({ question: q, answer: void 0, sourceTitle: void 0, sourceSite: void 0, sourceCite: void 0 }, 1, null, options.query));
|
|
1739
1747
|
}
|
|
1740
1748
|
}
|
|
1749
|
+
this.completeness.paaWithoutAnswer = results.filter((r) => !r.answer).length;
|
|
1750
|
+
this.completeness.paaWithoutSource = results.filter((r) => !r.source_title && !r.source_site && !r.source_cite).length;
|
|
1741
1751
|
return results;
|
|
1742
1752
|
}
|
|
1753
|
+
async fillIncompleteItems(page, orderedQs, itemMap, options) {
|
|
1754
|
+
const kept = new Set(orderedQs.slice(0, options.maxQuestions));
|
|
1755
|
+
const missingBefore = new Set([...kept].filter((q) => !itemMap.get(q)?.answer));
|
|
1756
|
+
if (missingBefore.size === 0) return;
|
|
1757
|
+
for (let round = 0; round < 2; round++) {
|
|
1758
|
+
if (options.softDeadlineMs && Date.now() >= options.softDeadlineMs) break;
|
|
1759
|
+
const stillMissing = [...missingBefore].filter((q) => !itemMap.get(q)?.answer);
|
|
1760
|
+
if (stillMissing.length === 0) break;
|
|
1761
|
+
const reExpanded = await this.reExpandCollapsedItems(page).catch(() => false);
|
|
1762
|
+
await page.waitForTimeout(reExpanded ? 900 : 500);
|
|
1763
|
+
let improved = false;
|
|
1764
|
+
for (const item of await this.extractVisibleItems(page)) {
|
|
1765
|
+
if (!kept.has(item.question)) continue;
|
|
1766
|
+
const existing = itemMap.get(item.question);
|
|
1767
|
+
if (!item.answer || existing?.answer) continue;
|
|
1768
|
+
itemMap.set(item.question, {
|
|
1769
|
+
...item,
|
|
1770
|
+
sourceTitle: item.sourceTitle ?? existing?.sourceTitle,
|
|
1771
|
+
sourceSite: item.sourceSite ?? existing?.sourceSite,
|
|
1772
|
+
sourceCite: item.sourceCite ?? existing?.sourceCite
|
|
1773
|
+
});
|
|
1774
|
+
improved = true;
|
|
1775
|
+
}
|
|
1776
|
+
if (!improved) break;
|
|
1777
|
+
}
|
|
1778
|
+
this.completeness.paaAnswersRecovered = [...missingBefore].filter((q) => itemMap.get(q)?.answer).length;
|
|
1779
|
+
}
|
|
1780
|
+
async reExpandCollapsedItems(page) {
|
|
1781
|
+
const unexpandedSel = `${PAASelectors.item}:not(.${PAASelectors.expandedClass}) ${PAASelectors.clickTarget}`;
|
|
1782
|
+
const count = await page.locator(unexpandedSel).count().catch(() => 0);
|
|
1783
|
+
if (count === 0) return false;
|
|
1784
|
+
for (let i = 0; i < count; i++) {
|
|
1785
|
+
try {
|
|
1786
|
+
const btn = page.locator(unexpandedSel).first();
|
|
1787
|
+
await btn.scrollIntoViewIfNeeded();
|
|
1788
|
+
await btn.click({ force: true });
|
|
1789
|
+
await page.waitForTimeout(300);
|
|
1790
|
+
} catch {
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
return true;
|
|
1794
|
+
}
|
|
1743
1795
|
async extractVideos(page) {
|
|
1744
1796
|
const vsels = VideoSelectors;
|
|
1745
1797
|
return page.evaluate((sels) => {
|
|
@@ -2074,12 +2126,58 @@ var PAAExtractor = class {
|
|
|
2074
2126
|
}
|
|
2075
2127
|
return { ...entityIds, entities: records, cids: [...cidSet] };
|
|
2076
2128
|
}
|
|
2077
|
-
async extractAISurfaces(page) {
|
|
2078
|
-
|
|
2129
|
+
async extractAISurfaces(page, options) {
|
|
2130
|
+
const surfaces = await page.evaluate(extractAISurfacesFromDocument, {
|
|
2079
2131
|
aio: AIOverviewSelectors,
|
|
2080
2132
|
aim: AIModeSelectors,
|
|
2081
2133
|
expandWaitMs: 1500
|
|
2082
2134
|
});
|
|
2135
|
+
if (!surfaces.aiOverview.detected) {
|
|
2136
|
+
this.completeness.aioShareCaptured = null;
|
|
2137
|
+
return surfaces;
|
|
2138
|
+
}
|
|
2139
|
+
const shareUrl = this.aioShareUrlEarly ?? await this.captureAIOverviewShareUrl(page, options).catch(() => null);
|
|
2140
|
+
this.completeness.aioShareCaptured = shareUrl !== null;
|
|
2141
|
+
return {
|
|
2142
|
+
...surfaces,
|
|
2143
|
+
aiOverview: { ...surfaces.aiOverview, shareUrl }
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
async captureAIOverviewShareUrl(page, options) {
|
|
2147
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
2148
|
+
if (options?.softDeadlineMs && Date.now() >= options.softDeadlineMs) return null;
|
|
2149
|
+
const clicked = await page.evaluate(() => {
|
|
2150
|
+
const heads = Array.from(document.querySelectorAll('h1,h2,h3,[role="heading"],div')).filter((h) => (h.textContent || "").trim() === "AI Overview");
|
|
2151
|
+
for (const head of heads) {
|
|
2152
|
+
let sec = head;
|
|
2153
|
+
for (let up = 0; up < 8 && sec; up++) {
|
|
2154
|
+
const btn = sec.querySelector('[aria-label="Share"]');
|
|
2155
|
+
if (btn) {
|
|
2156
|
+
btn.scrollIntoView({ block: "center" });
|
|
2157
|
+
btn.click();
|
|
2158
|
+
return true;
|
|
2159
|
+
}
|
|
2160
|
+
sec = sec.parentElement;
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
return false;
|
|
2164
|
+
}).catch(() => false);
|
|
2165
|
+
if (!clicked) return null;
|
|
2166
|
+
await page.waitForTimeout(4500);
|
|
2167
|
+
const url = await page.evaluate(() => {
|
|
2168
|
+
const w = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
2169
|
+
while (w.nextNode()) {
|
|
2170
|
+
const m = (w.currentNode.textContent || "").match(/https:\/\/share\.google\/aimode\/\S+/);
|
|
2171
|
+
if (m) return m[0];
|
|
2172
|
+
}
|
|
2173
|
+
return null;
|
|
2174
|
+
}).catch(() => null);
|
|
2175
|
+
await page.keyboard.press("Escape").catch(() => {
|
|
2176
|
+
});
|
|
2177
|
+
if (url) return url;
|
|
2178
|
+
await page.waitForTimeout(600);
|
|
2179
|
+
}
|
|
2180
|
+
return null;
|
|
2083
2181
|
}
|
|
2084
2182
|
buildTree(flat, _seed) {
|
|
2085
2183
|
const roots = [];
|
|
@@ -2132,6 +2230,8 @@ var PAAExtractor = class {
|
|
|
2132
2230
|
}
|
|
2133
2231
|
async extract(options, signal) {
|
|
2134
2232
|
const startMs = Date.now();
|
|
2233
|
+
this.completeness = { paaWithoutAnswer: 0, paaWithoutSource: 0, paaAnswersRecovered: 0, aioShareCaptured: null };
|
|
2234
|
+
this.aioShareUrlEarly = null;
|
|
2135
2235
|
const isMobile = options.device === "mobile";
|
|
2136
2236
|
const config = {
|
|
2137
2237
|
headless: options.headless,
|
|
@@ -2170,6 +2270,7 @@ var PAAExtractor = class {
|
|
|
2170
2270
|
this.throwIfAborted(signal);
|
|
2171
2271
|
const page = this.driver.getPage();
|
|
2172
2272
|
await this.throwIfCaptcha(page, "Google SERP");
|
|
2273
|
+
this.aioShareUrlEarly = await this.captureAIOverviewShareUrl(page, options).catch(() => null);
|
|
2173
2274
|
if (options.serpOnly) {
|
|
2174
2275
|
const [organicResults2, localPack2, rawEntityIds2] = await Promise.all([
|
|
2175
2276
|
this.extractOrganicResults(page),
|
|
@@ -2177,7 +2278,7 @@ var PAAExtractor = class {
|
|
|
2177
2278
|
this.extractEntityIds(page)
|
|
2178
2279
|
]);
|
|
2179
2280
|
const entityIds2 = this.mergeLocalPackIntoEntities(rawEntityIds2, localPack2);
|
|
2180
|
-
const aiSurfaces2 = await this.extractAISurfaces(page);
|
|
2281
|
+
const aiSurfaces2 = await this.extractAISurfaces(page, options);
|
|
2181
2282
|
let locationEvidence2 = options.debug ? inferSerpLocationEvidence(canonicalLocation, organicResults2, localPack2) : void 0;
|
|
2182
2283
|
let allOrganic2 = organicResults2;
|
|
2183
2284
|
if ((options.pages ?? 1) >= 2) {
|
|
@@ -2206,6 +2307,7 @@ var PAAExtractor = class {
|
|
|
2206
2307
|
diagnostics: {
|
|
2207
2308
|
completionStatus: "serp_only",
|
|
2208
2309
|
problem: null,
|
|
2310
|
+
completeness: { ...this.completeness },
|
|
2209
2311
|
...options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence2) } : {}
|
|
2210
2312
|
},
|
|
2211
2313
|
totalQuestions: 0,
|
|
@@ -2249,7 +2351,7 @@ var PAAExtractor = class {
|
|
|
2249
2351
|
locationEvidence2 = inferSerpLocationEvidence(canonicalLocation, noPaaOrganic, localPack);
|
|
2250
2352
|
}
|
|
2251
2353
|
}
|
|
2252
|
-
const aiSurfaces2 = await this.extractAISurfaces(page);
|
|
2354
|
+
const aiSurfaces2 = await this.extractAISurfaces(page, options);
|
|
2253
2355
|
const stats2 = {
|
|
2254
2356
|
seed: options.query,
|
|
2255
2357
|
totalQuestions: 0,
|
|
@@ -2265,6 +2367,7 @@ var PAAExtractor = class {
|
|
|
2265
2367
|
diagnostics: {
|
|
2266
2368
|
completionStatus: "no_paa",
|
|
2267
2369
|
problem: null,
|
|
2370
|
+
completeness: { ...this.completeness },
|
|
2268
2371
|
...options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence2) } : {}
|
|
2269
2372
|
},
|
|
2270
2373
|
totalQuestions: 0,
|
|
@@ -2284,7 +2387,7 @@ var PAAExtractor = class {
|
|
|
2284
2387
|
}
|
|
2285
2388
|
const flat = await this.runBFS(page, options, signal);
|
|
2286
2389
|
this.throwIfAborted(signal);
|
|
2287
|
-
const aiSurfaces = await this.extractAISurfaces(page);
|
|
2390
|
+
const aiSurfaces = await this.extractAISurfaces(page, options);
|
|
2288
2391
|
const shortVidsParams = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, pws: "0", udm: ShortVideoSelectors.udm });
|
|
2289
2392
|
if (uule) shortVidsParams.set("uule", uule);
|
|
2290
2393
|
let shortVideos = [];
|
|
@@ -2331,6 +2434,7 @@ var PAAExtractor = class {
|
|
|
2331
2434
|
diagnostics: {
|
|
2332
2435
|
completionStatus: "paa_found",
|
|
2333
2436
|
problem: null,
|
|
2437
|
+
completeness: { ...this.completeness },
|
|
2334
2438
|
...diagnosticWarnings.length > 0 ? { warnings: diagnosticWarnings } : {},
|
|
2335
2439
|
...options.debug ? { debug: this.buildHarvestDebugSnapshot(options, canonicalLocation, uule, locationEvidence) } : {}
|
|
2336
2440
|
},
|