mcp-scraper 0.32.0 → 0.32.2
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/README.md +1 -1
- package/dist/bin/api-server.cjs +61 -34
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +3 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +3 -3
- 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 +3 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/bin/paa-harvest.cjs +4 -2
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-RDCCU7CQ.js → chunk-AEMABLEL.js} +5 -4
- package/dist/chunk-AEMABLEL.js.map +1 -0
- package/dist/{chunk-55M5CE5L.js → chunk-MKZIL4EA.js} +2 -2
- package/dist/{chunk-PTHY7NYD.js → chunk-V73MPRU6.js} +3 -1
- package/dist/chunk-V73MPRU6.js.map +1 -0
- package/dist/{chunk-YOOEAXWP.js → chunk-XEED325T.js} +3 -3
- package/dist/chunk-XLO5CZ6T.js +7 -0
- package/dist/chunk-XLO5CZ6T.js.map +1 -0
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{server-OBOTNFD6.js → server-LTZDJHFG.js} +63 -38
- package/dist/{server-OBOTNFD6.js.map → server-LTZDJHFG.js.map} +1 -1
- package/dist/{worker-7DJYUACV.js → worker-ZZCZNY3R.js} +3 -3
- package/docs/mcp-tool-manifest.generated.json +2 -2
- package/package.json +1 -1
- package/dist/chunk-CPQF3PYW.js +0 -7
- package/dist/chunk-CPQF3PYW.js.map +0 -1
- package/dist/chunk-PTHY7NYD.js.map +0 -1
- package/dist/chunk-RDCCU7CQ.js.map +0 -1
- /package/dist/{chunk-55M5CE5L.js.map → chunk-MKZIL4EA.js.map} +0 -0
- /package/dist/{chunk-YOOEAXWP.js.map → chunk-XEED325T.js.map} +0 -0
- /package/dist/{worker-7DJYUACV.js.map → worker-ZZCZNY3R.js.map} +0 -0
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ Build the branded one-click bundle:
|
|
|
88
88
|
npm run build:mcpb
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.32.
|
|
91
|
+
The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.32.2`, SHA-256 `e4bcf7d1e722ab821eaceebb5acba77e19e3e7bba1326c3d41f77cb22a70f793`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
|
|
92
92
|
|
|
93
93
|
The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
|
|
94
94
|
|
package/dist/bin/api-server.cjs
CHANGED
|
@@ -13834,8 +13834,8 @@ function positiveIntFromEnv(name, fallback) {
|
|
|
13834
13834
|
function proxyIdSuffix(proxyId) {
|
|
13835
13835
|
return proxyId ? proxyId.slice(-6) : null;
|
|
13836
13836
|
}
|
|
13837
|
-
function serpArrivalUrl(googleUrl) {
|
|
13838
|
-
const base = process.env.SERP_REDIRECT_BASE?.trim().replace(/\/+$/, "");
|
|
13837
|
+
function serpArrivalUrl(googleUrl, baseOverride) {
|
|
13838
|
+
const base = (baseOverride ?? process.env.SERP_REDIRECT_BASE)?.trim().replace(/\/+$/, "");
|
|
13839
13839
|
if (!base) return googleUrl;
|
|
13840
13840
|
return `${base}/g/${Buffer.from(googleUrl, "utf8").toString("base64url")}`;
|
|
13841
13841
|
}
|
|
@@ -17394,6 +17394,8 @@ var init_schemas3 = __esm({
|
|
|
17394
17394
|
includeServices: import_zod17.z.boolean().default(false),
|
|
17395
17395
|
proxyMode: import_zod17.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
|
|
17396
17396
|
proxyZip: import_zod17.z.string().regex(/^\d{5}$/).optional(),
|
|
17397
|
+
serpRedirect: import_zod17.z.boolean().optional(),
|
|
17398
|
+
forceDirectEgress: import_zod17.z.boolean().optional(),
|
|
17397
17399
|
debug: import_zod17.z.boolean().default(false),
|
|
17398
17400
|
kernelApiKey: import_zod17.z.string().optional(),
|
|
17399
17401
|
kernelProxyId: import_zod17.z.string().optional(),
|
|
@@ -19260,14 +19262,16 @@ function buildGoogleOrganicSearchUrl(input) {
|
|
|
19260
19262
|
if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
|
|
19261
19263
|
return `https://www.google.com/search?${params.toString()}`;
|
|
19262
19264
|
}
|
|
19263
|
-
var LOCAL_RESULTS_PAGE_LIMIT, LOCAL_RESULTS_WAIT_MS, MapsSearchExtractor;
|
|
19265
|
+
var LOCAL_RESULTS_PAGE_LIMIT, LOCAL_RESULTS_WAIT_MS, MAPS_REDIRECT_BASE, MapsSearchExtractor;
|
|
19264
19266
|
var init_MapsSearchExtractor = __esm({
|
|
19265
19267
|
"src/extractor/MapsSearchExtractor.ts"() {
|
|
19266
19268
|
"use strict";
|
|
19267
19269
|
init_errors();
|
|
19270
|
+
init_BrowserDriver();
|
|
19268
19271
|
init_uule();
|
|
19269
19272
|
LOCAL_RESULTS_PAGE_LIMIT = 8;
|
|
19270
19273
|
LOCAL_RESULTS_WAIT_MS = 1e3;
|
|
19274
|
+
MAPS_REDIRECT_BASE = "https://serp-redirector.vercel.app";
|
|
19271
19275
|
MapsSearchExtractor = class {
|
|
19272
19276
|
constructor(driver) {
|
|
19273
19277
|
this.driver = driver;
|
|
@@ -19277,21 +19281,23 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19277
19281
|
const startMs = Date.now();
|
|
19278
19282
|
const searchQuery = [options.query, options.location].filter(Boolean).join(" ");
|
|
19279
19283
|
const searchUrl = buildGoogleOrganicSearchUrl(options);
|
|
19284
|
+
const keepDefaultProxy = !options.forceDirectEgress && options.proxyMode !== "location" && options.proxyMode !== "configured" && !options.kernelProxyId;
|
|
19280
19285
|
const config = {
|
|
19281
19286
|
headless: options.headless,
|
|
19282
19287
|
kernelApiKey: options.kernelApiKey,
|
|
19283
19288
|
kernelProxyId: options.kernelProxyId,
|
|
19284
19289
|
kernelProxyResolution: options.kernelProxyResolution,
|
|
19285
19290
|
proxyMode: options.proxyMode,
|
|
19286
|
-
keepDefaultProxy
|
|
19291
|
+
keepDefaultProxy,
|
|
19287
19292
|
viewport: { width: 1280, height: 900 },
|
|
19288
19293
|
locale: `${options.hl}-${options.gl.toUpperCase()}`,
|
|
19289
19294
|
debug: options.debug
|
|
19290
19295
|
};
|
|
19296
|
+
const navUrl = options.serpRedirect ? serpArrivalUrl(searchUrl, process.env.SERP_REDIRECT_BASE?.trim() || MAPS_REDIRECT_BASE) : searchUrl;
|
|
19291
19297
|
try {
|
|
19292
19298
|
await this.driver.launch(config);
|
|
19293
19299
|
const page = this.driver.getPage();
|
|
19294
|
-
await page.goto(
|
|
19300
|
+
await page.goto(navUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
19295
19301
|
await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
|
|
19296
19302
|
if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
|
|
19297
19303
|
const reachedFinder = await this.clickIntoLocalFinder(page);
|
|
@@ -19378,29 +19384,38 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19378
19384
|
};
|
|
19379
19385
|
const phonePattern = /(?:\+?1[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}/;
|
|
19380
19386
|
const addressPattern = /\b[A-Z]{2}\s+\d{5}(?:-\d{4})?\b|\b(?:St|Street|Ave|Avenue|Rd|Road|Blvd|Boulevard|Dr|Drive|Ln|Lane|Way|Pkwy|Parkway)\b/i;
|
|
19381
|
-
const
|
|
19382
|
-
const
|
|
19383
|
-
return Boolean(
|
|
19387
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]')).filter((heading) => {
|
|
19388
|
+
const text2 = normalize4(heading.textContent);
|
|
19389
|
+
return Boolean(text2) && !/^(?:businesses|places|sponsored|people also ask|discussions and forums|more businesses|more places|custom date range|choose what you)/i.test(text2 ?? "");
|
|
19384
19390
|
});
|
|
19385
19391
|
const seen = /* @__PURE__ */ new Set();
|
|
19386
19392
|
const out = [];
|
|
19387
|
-
|
|
19388
|
-
|
|
19393
|
+
let cardIndex = -1;
|
|
19394
|
+
for (const heading of headings) {
|
|
19395
|
+
let card = heading;
|
|
19396
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
19397
|
+
const parent = card.parentElement;
|
|
19398
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
19399
|
+
card = parent;
|
|
19400
|
+
}
|
|
19401
|
+
if (card.closest('[role="dialog"], dialog')) continue;
|
|
19402
|
+
const name = normalize4(heading.textContent);
|
|
19389
19403
|
if (!name) continue;
|
|
19390
|
-
const
|
|
19391
|
-
|
|
19404
|
+
const lines = (card.innerText ?? "").split("\n").map((line) => normalize4(line)).filter((line) => Boolean(line));
|
|
19405
|
+
if (/^sponsored$/i.test(lines[0] ?? "")) continue;
|
|
19406
|
+
const ratingLine = lines.find((line) => /\d(?:\.\d)?\s*\(/.test(line)) ?? "";
|
|
19407
|
+
const rating = ratingLine.match(/(\d(?:\.\d)?)\s*\(/)?.[1] ?? null;
|
|
19408
|
+
const reviewCount = ratingLine.match(/\((\d[\d,]*)\)/)?.[1]?.replace(/,/g, "") ?? null;
|
|
19409
|
+
const category = normalize4(ratingLine.split("\xB7").slice(1).join("\xB7"));
|
|
19410
|
+
const phone = lines.map((line) => line.match(phonePattern)?.[0]).find((value) => Boolean(value)) ?? null;
|
|
19411
|
+
const hoursStatus = normalize4((lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? "").split("\xB7")[0] ?? "");
|
|
19412
|
+
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
19413
|
+
const websiteUrl = Array.from(card.querySelectorAll("a[href]")).map((anchor) => anchor.href).find((href) => /^https?:/i.test(href) && !/google\.|gstatic|googleusercontent/.test(href)) ?? null;
|
|
19414
|
+
if (!rating && !(phone && websiteUrl)) continue;
|
|
19415
|
+
const key = `${name.toLowerCase()}|${lines.join(" ").toLowerCase()}`;
|
|
19392
19416
|
if (seen.has(key)) continue;
|
|
19393
19417
|
seen.add(key);
|
|
19394
|
-
|
|
19395
|
-
const aria = normalize4(card.getAttribute("aria-label"));
|
|
19396
|
-
const rating = (aria ?? text2).match(/(?:rated\s+)?(\d(?:\.\d)?)\s*(?:out of 5)?/i)?.[1] ?? null;
|
|
19397
|
-
const reviewCount = (aria ?? text2).match(/(?:\(|·\s*)([\d,]+)\s+(?:user\s+)?reviews?\b/i)?.[1]?.replace(/,/g, "") ?? null;
|
|
19398
|
-
const phone = lines.find((line) => phonePattern.test(line)) ?? null;
|
|
19399
|
-
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
19400
|
-
const hoursStatus = lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? null;
|
|
19401
|
-
const category = lines.find(
|
|
19402
|
-
(line) => line !== name && line !== phone && line !== address && line !== hoursStatus && !/^(?:rated|\d[\d.,]*\s*(?:out of 5|reviews?)?)\b/i.test(line) && !/sponsored|website|directions|call|save|share|more/i.test(line)
|
|
19403
|
-
) ?? null;
|
|
19418
|
+
cardIndex += 1;
|
|
19404
19419
|
const mapsSearchUrl = `https://www.google.com/maps/search/${encodeURIComponent([name, locationHint].filter(Boolean).join(" "))}`;
|
|
19405
19420
|
out.push({
|
|
19406
19421
|
cardIndex,
|
|
@@ -19415,7 +19430,7 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19415
19430
|
address,
|
|
19416
19431
|
phone,
|
|
19417
19432
|
hoursStatus,
|
|
19418
|
-
websiteUrl
|
|
19433
|
+
websiteUrl,
|
|
19419
19434
|
directionsUrl: `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent([name, address].filter(Boolean).join(", "))}`,
|
|
19420
19435
|
metadata: lines.slice(0, 20)
|
|
19421
19436
|
});
|
|
@@ -19424,17 +19439,27 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19424
19439
|
}, fallbackLocation);
|
|
19425
19440
|
}
|
|
19426
19441
|
async openCardAndExtractDialog(page, card, includeServices) {
|
|
19442
|
+
if (!includeServices) return null;
|
|
19427
19443
|
const clicked = await page.evaluate((input) => {
|
|
19428
19444
|
const normalize4 = (value) => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
19429
|
-
const
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
19437
|
-
|
|
19445
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]'));
|
|
19446
|
+
for (const heading of headings) {
|
|
19447
|
+
let target = heading;
|
|
19448
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
19449
|
+
const parent = target.parentElement;
|
|
19450
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
19451
|
+
target = parent;
|
|
19452
|
+
}
|
|
19453
|
+
if (target.closest('[role="dialog"], dialog')) continue;
|
|
19454
|
+
const name = normalize4(heading.textContent);
|
|
19455
|
+
if (!name) continue;
|
|
19456
|
+
const lines = (target.innerText ?? "").split("\n").map((line) => normalize4(line)).filter(Boolean);
|
|
19457
|
+
if (`${name}|${lines.join(" ")}` !== input.cardKey) continue;
|
|
19458
|
+
target.click();
|
|
19459
|
+
return true;
|
|
19460
|
+
}
|
|
19461
|
+
return false;
|
|
19462
|
+
}, { cardKey: card.cardKey });
|
|
19438
19463
|
if (!clicked) return null;
|
|
19439
19464
|
const dialog = page.locator('dialog, [role="dialog"]').filter({ has: page.locator('h1, h2, [role="heading"]') }).last();
|
|
19440
19465
|
await dialog.waitFor({ state: "visible", timeout: 6e3 }).catch(() => {
|
|
@@ -20145,7 +20170,9 @@ async function runMapsSearchWithRotation(options) {
|
|
|
20145
20170
|
...options,
|
|
20146
20171
|
proxyZip,
|
|
20147
20172
|
kernelProxyId: options.proxyMode === "none" ? void 0 : resolution2.kernelProxyId,
|
|
20148
|
-
kernelProxyResolution: resolution2.resolution
|
|
20173
|
+
kernelProxyResolution: resolution2.resolution,
|
|
20174
|
+
serpRedirect: options.proxyMode === "none" && attemptIndex >= 1 && attemptIndex < maxAttempts - 1,
|
|
20175
|
+
forceDirectEgress: options.proxyMode === "none" && attemptIndex >= 1
|
|
20149
20176
|
};
|
|
20150
20177
|
const isHeadfulEscalation = attemptIndex === maxAttempts - 1;
|
|
20151
20178
|
const baseCtx = currentCostContext();
|
|
@@ -29767,7 +29794,7 @@ var PACKAGE_VERSION;
|
|
|
29767
29794
|
var init_version = __esm({
|
|
29768
29795
|
"src/version.ts"() {
|
|
29769
29796
|
"use strict";
|
|
29770
|
-
PACKAGE_VERSION = "0.32.
|
|
29797
|
+
PACKAGE_VERSION = "0.32.2";
|
|
29771
29798
|
}
|
|
29772
29799
|
});
|
|
29773
29800
|
|