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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/api-server.cjs +61 -34
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +2 -2
  5. package/dist/bin/mcp-scraper-cli.cjs +3 -1
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +3 -3
  8. package/dist/bin/mcp-scraper-install.cjs +1 -1
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +1 -1
  11. package/dist/bin/mcp-stdio-server.cjs +3 -1
  12. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-stdio-server.js +3 -3
  14. package/dist/bin/paa-harvest.cjs +4 -2
  15. package/dist/bin/paa-harvest.cjs.map +1 -1
  16. package/dist/bin/paa-harvest.js +2 -2
  17. package/dist/{chunk-RDCCU7CQ.js → chunk-AEMABLEL.js} +5 -4
  18. package/dist/chunk-AEMABLEL.js.map +1 -0
  19. package/dist/{chunk-55M5CE5L.js → chunk-MKZIL4EA.js} +2 -2
  20. package/dist/{chunk-PTHY7NYD.js → chunk-V73MPRU6.js} +3 -1
  21. package/dist/chunk-V73MPRU6.js.map +1 -0
  22. package/dist/{chunk-YOOEAXWP.js → chunk-XEED325T.js} +3 -3
  23. package/dist/chunk-XLO5CZ6T.js +7 -0
  24. package/dist/chunk-XLO5CZ6T.js.map +1 -0
  25. package/dist/index.cjs +4 -2
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +2 -2
  28. package/dist/{server-OBOTNFD6.js → server-LTZDJHFG.js} +63 -38
  29. package/dist/{server-OBOTNFD6.js.map → server-LTZDJHFG.js.map} +1 -1
  30. package/dist/{worker-7DJYUACV.js → worker-ZZCZNY3R.js} +3 -3
  31. package/docs/mcp-tool-manifest.generated.json +2 -2
  32. package/package.json +1 -1
  33. package/dist/chunk-CPQF3PYW.js +0 -7
  34. package/dist/chunk-CPQF3PYW.js.map +0 -1
  35. package/dist/chunk-PTHY7NYD.js.map +0 -1
  36. package/dist/chunk-RDCCU7CQ.js.map +0 -1
  37. /package/dist/{chunk-55M5CE5L.js.map → chunk-MKZIL4EA.js.map} +0 -0
  38. /package/dist/{chunk-YOOEAXWP.js.map → chunk-XEED325T.js.map} +0 -0
  39. /package/dist/{worker-7DJYUACV.js.map → worker-ZZCZNY3R.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  harvest
3
- } from "./chunk-RDCCU7CQ.js";
3
+ } from "./chunk-AEMABLEL.js";
4
4
  import {
5
5
  recordVendorUsage
6
6
  } from "./chunk-MTSBI7ZH.js";
7
7
  import "./chunk-K443GQY5.js";
8
- import "./chunk-PTHY7NYD.js";
8
+ import "./chunk-V73MPRU6.js";
9
9
  import "./chunk-M2S27J6Z.js";
10
10
  import "./chunk-ICT7DDHL.js";
11
11
 
@@ -15,8 +15,9 @@ import {
15
15
  encodeUule,
16
16
  harvest,
17
17
  normalizeLocation,
18
- resolveKernelProxyId
19
- } from "./chunk-RDCCU7CQ.js";
18
+ resolveKernelProxyId,
19
+ serpArrivalUrl
20
+ } from "./chunk-AEMABLEL.js";
20
21
  import {
21
22
  HttpMcpToolExecutor,
22
23
  assessTranscriptSignal,
@@ -36,7 +37,7 @@ import {
36
37
  sanitizeAttempts,
37
38
  sanitizeHarvestResult,
38
39
  transcribeMediaUrl
39
- } from "./chunk-YOOEAXWP.js";
40
+ } from "./chunk-XEED325T.js";
40
41
  import {
41
42
  auditImages,
42
43
  buildLinkReport,
@@ -65,7 +66,7 @@ import {
65
66
  workflowOutputBaseDir,
66
67
  workflowStepCount,
67
68
  workflowSupportsSteps
68
- } from "./chunk-55M5CE5L.js";
69
+ } from "./chunk-MKZIL4EA.js";
69
70
  import "./chunk-K443GQY5.js";
70
71
  import {
71
72
  DEFAULT_MAPS_PROXY_MODE,
@@ -76,8 +77,8 @@ import {
76
77
  RawMapsHoursRowSchema,
77
78
  RawMapsOverviewSchema,
78
79
  RawMapsReviewStatsSchema
79
- } from "./chunk-PTHY7NYD.js";
80
- import "./chunk-CPQF3PYW.js";
80
+ } from "./chunk-V73MPRU6.js";
81
+ import "./chunk-XLO5CZ6T.js";
81
82
  import {
82
83
  completeExtractJob,
83
84
  countSuccessfulPages,
@@ -13083,6 +13084,7 @@ import { Hono as Hono11 } from "hono";
13083
13084
  // src/extractor/MapsSearchExtractor.ts
13084
13085
  var LOCAL_RESULTS_PAGE_LIMIT = 8;
13085
13086
  var LOCAL_RESULTS_WAIT_MS = 1e3;
13087
+ var MAPS_REDIRECT_BASE = "https://serp-redirector.vercel.app";
13086
13088
  function buildGoogleLocalResultsUrl(input) {
13087
13089
  const query = [input.query, input.location].filter(Boolean).join(" ");
13088
13090
  const params = new URLSearchParams({ q: query, udm: "1", gl: input.gl, hl: input.hl, pws: "0" });
@@ -13104,21 +13106,23 @@ var MapsSearchExtractor = class {
13104
13106
  const startMs = Date.now();
13105
13107
  const searchQuery = [options.query, options.location].filter(Boolean).join(" ");
13106
13108
  const searchUrl = buildGoogleOrganicSearchUrl(options);
13109
+ const keepDefaultProxy = !options.forceDirectEgress && options.proxyMode !== "location" && options.proxyMode !== "configured" && !options.kernelProxyId;
13107
13110
  const config = {
13108
13111
  headless: options.headless,
13109
13112
  kernelApiKey: options.kernelApiKey,
13110
13113
  kernelProxyId: options.kernelProxyId,
13111
13114
  kernelProxyResolution: options.kernelProxyResolution,
13112
13115
  proxyMode: options.proxyMode,
13113
- keepDefaultProxy: options.proxyMode !== "location" && options.proxyMode !== "configured" && !options.kernelProxyId,
13116
+ keepDefaultProxy,
13114
13117
  viewport: { width: 1280, height: 900 },
13115
13118
  locale: `${options.hl}-${options.gl.toUpperCase()}`,
13116
13119
  debug: options.debug
13117
13120
  };
13121
+ const navUrl = options.serpRedirect ? serpArrivalUrl(searchUrl, process.env.SERP_REDIRECT_BASE?.trim() || MAPS_REDIRECT_BASE) : searchUrl;
13118
13122
  try {
13119
13123
  await this.driver.launch(config);
13120
13124
  const page = this.driver.getPage();
13121
- await page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
13125
+ await page.goto(navUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
13122
13126
  await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
13123
13127
  if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
13124
13128
  const reachedFinder = await this.clickIntoLocalFinder(page);
@@ -13205,29 +13209,38 @@ var MapsSearchExtractor = class {
13205
13209
  };
13206
13210
  const phonePattern = /(?:\+?1[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}/;
13207
13211
  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;
13208
- const cards = Array.from(document.querySelectorAll("button")).filter((button) => {
13209
- const name = normalize(button.querySelector("h3")?.textContent);
13210
- return Boolean(name) && !button.closest('[role="dialog"], dialog') && !/\bsponsored\b/i.test(button.innerText);
13212
+ const headings = Array.from(document.querySelectorAll('div[role="heading"]')).filter((heading) => {
13213
+ const text2 = normalize(heading.textContent);
13214
+ 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 ?? "");
13211
13215
  });
13212
13216
  const seen = /* @__PURE__ */ new Set();
13213
13217
  const out = [];
13214
- for (const [cardIndex, card] of cards.entries()) {
13215
- const name = normalize(card.querySelector("h3")?.textContent);
13218
+ let cardIndex = -1;
13219
+ for (const heading of headings) {
13220
+ let card = heading;
13221
+ for (let hop = 0; hop < 8; hop++) {
13222
+ const parent = card.parentElement;
13223
+ if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
13224
+ card = parent;
13225
+ }
13226
+ if (card.closest('[role="dialog"], dialog')) continue;
13227
+ const name = normalize(heading.textContent);
13216
13228
  if (!name) continue;
13217
- const text2 = normalize(card.innerText) ?? name;
13218
- const key = `${name.toLowerCase()}|${text2.toLowerCase()}`;
13229
+ const lines = (card.innerText ?? "").split("\n").map((line) => normalize(line)).filter((line) => Boolean(line));
13230
+ if (/^sponsored$/i.test(lines[0] ?? "")) continue;
13231
+ const ratingLine = lines.find((line) => /\d(?:\.\d)?\s*\(/.test(line)) ?? "";
13232
+ const rating = ratingLine.match(/(\d(?:\.\d)?)\s*\(/)?.[1] ?? null;
13233
+ const reviewCount = ratingLine.match(/\((\d[\d,]*)\)/)?.[1]?.replace(/,/g, "") ?? null;
13234
+ const category = normalize(ratingLine.split("\xB7").slice(1).join("\xB7"));
13235
+ const phone = lines.map((line) => line.match(phonePattern)?.[0]).find((value) => Boolean(value)) ?? null;
13236
+ const hoursStatus = normalize((lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? "").split("\xB7")[0] ?? "");
13237
+ const address = lines.find((line) => addressPattern.test(line)) ?? null;
13238
+ const websiteUrl = Array.from(card.querySelectorAll("a[href]")).map((anchor) => anchor.href).find((href) => /^https?:/i.test(href) && !/google\.|gstatic|googleusercontent/.test(href)) ?? null;
13239
+ if (!rating && !(phone && websiteUrl)) continue;
13240
+ const key = `${name.toLowerCase()}|${lines.join(" ").toLowerCase()}`;
13219
13241
  if (seen.has(key)) continue;
13220
13242
  seen.add(key);
13221
- const lines = text2.split(/\n+/).map((line) => normalize(line)).filter((line) => Boolean(line));
13222
- const aria = normalize(card.getAttribute("aria-label"));
13223
- const rating = (aria ?? text2).match(/(?:rated\s+)?(\d(?:\.\d)?)\s*(?:out of 5)?/i)?.[1] ?? null;
13224
- const reviewCount = (aria ?? text2).match(/(?:\(|·\s*)([\d,]+)\s+(?:user\s+)?reviews?\b/i)?.[1]?.replace(/,/g, "") ?? null;
13225
- const phone = lines.find((line) => phonePattern.test(line)) ?? null;
13226
- const address = lines.find((line) => addressPattern.test(line)) ?? null;
13227
- const hoursStatus = lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? null;
13228
- const category = lines.find(
13229
- (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)
13230
- ) ?? null;
13243
+ cardIndex += 1;
13231
13244
  const mapsSearchUrl = `https://www.google.com/maps/search/${encodeURIComponent([name, locationHint].filter(Boolean).join(" "))}`;
13232
13245
  out.push({
13233
13246
  cardIndex,
@@ -13242,7 +13255,7 @@ var MapsSearchExtractor = class {
13242
13255
  address,
13243
13256
  phone,
13244
13257
  hoursStatus,
13245
- websiteUrl: null,
13258
+ websiteUrl,
13246
13259
  directionsUrl: `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent([name, address].filter(Boolean).join(", "))}`,
13247
13260
  metadata: lines.slice(0, 20)
13248
13261
  });
@@ -13251,17 +13264,27 @@ var MapsSearchExtractor = class {
13251
13264
  }, fallbackLocation);
13252
13265
  }
13253
13266
  async openCardAndExtractDialog(page, card, includeServices) {
13267
+ if (!includeServices) return null;
13254
13268
  const clicked = await page.evaluate((input) => {
13255
13269
  const normalize = (value) => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
13256
- const cards = Array.from(document.querySelectorAll("button")).filter(
13257
- (button) => Boolean(button.querySelector("h3")) && !button.closest('[role="dialog"], dialog') && !/\bsponsored\b/i.test(button.innerText)
13258
- );
13259
- const exact = cards.find((button) => `${normalize(button.querySelector("h3")?.textContent)}|${normalize(button.innerText)}` === input.cardKey);
13260
- const target = exact ?? cards[input.cardIndex];
13261
- if (!target) return false;
13262
- target.click();
13263
- return true;
13264
- }, { cardIndex: card.cardIndex, cardKey: card.cardKey });
13270
+ const headings = Array.from(document.querySelectorAll('div[role="heading"]'));
13271
+ for (const heading of headings) {
13272
+ let target = heading;
13273
+ for (let hop = 0; hop < 8; hop++) {
13274
+ const parent = target.parentElement;
13275
+ if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
13276
+ target = parent;
13277
+ }
13278
+ if (target.closest('[role="dialog"], dialog')) continue;
13279
+ const name = normalize(heading.textContent);
13280
+ if (!name) continue;
13281
+ const lines = (target.innerText ?? "").split("\n").map((line) => normalize(line)).filter(Boolean);
13282
+ if (`${name}|${lines.join(" ")}` !== input.cardKey) continue;
13283
+ target.click();
13284
+ return true;
13285
+ }
13286
+ return false;
13287
+ }, { cardKey: card.cardKey });
13265
13288
  if (!clicked) return null;
13266
13289
  const dialog = page.locator('dialog, [role="dialog"]').filter({ has: page.locator('h1, h2, [role="heading"]') }).last();
13267
13290
  await dialog.waitFor({ state: "visible", timeout: 6e3 }).catch(() => {
@@ -13959,7 +13982,9 @@ async function runMapsSearchWithRotation(options) {
13959
13982
  ...options,
13960
13983
  proxyZip,
13961
13984
  kernelProxyId: options.proxyMode === "none" ? void 0 : resolution.kernelProxyId,
13962
- kernelProxyResolution: resolution.resolution
13985
+ kernelProxyResolution: resolution.resolution,
13986
+ serpRedirect: options.proxyMode === "none" && attemptIndex >= 1 && attemptIndex < maxAttempts - 1,
13987
+ forceDirectEgress: options.proxyMode === "none" && attemptIndex >= 1
13963
13988
  };
13964
13989
  const isHeadfulEscalation = attemptIndex === maxAttempts - 1;
13965
13990
  const baseCtx = currentCostContext();
@@ -27405,7 +27430,7 @@ app.get("/cron/tick", async (c) => {
27405
27430
  if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
27406
27431
  return c.json({ error: "Unauthorized" }, 401);
27407
27432
  }
27408
- const { drainQueue } = await import("./worker-7DJYUACV.js");
27433
+ const { drainQueue } = await import("./worker-ZZCZNY3R.js");
27409
27434
  const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
27410
27435
  const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
27411
27436
  const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup] = await Promise.all([
@@ -27608,4 +27633,4 @@ app.get("/blog/:slug/", (c) => {
27608
27633
  export {
27609
27634
  app
27610
27635
  };
27611
- //# sourceMappingURL=server-OBOTNFD6.js.map
27636
+ //# sourceMappingURL=server-LTZDJHFG.js.map