auspex 0.2.1 → 0.3.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.
Files changed (101) hide show
  1. package/package.json +3 -1
  2. package/dist/agent/actions.d.ts +0 -5
  3. package/dist/agent/actions.d.ts.map +0 -1
  4. package/dist/agent/actions.js +0 -32
  5. package/dist/agent/actions.js.map +0 -1
  6. package/dist/agent/agent.d.ts +0 -26
  7. package/dist/agent/agent.d.ts.map +0 -1
  8. package/dist/agent/agent.js +0 -282
  9. package/dist/agent/agent.js.map +0 -1
  10. package/dist/agent/logger.d.ts +0 -15
  11. package/dist/agent/logger.d.ts.map +0 -1
  12. package/dist/agent/logger.js +0 -70
  13. package/dist/agent/logger.js.map +0 -1
  14. package/dist/agent/loop.d.ts +0 -21
  15. package/dist/agent/loop.d.ts.map +0 -1
  16. package/dist/agent/loop.js +0 -250
  17. package/dist/agent/loop.js.map +0 -1
  18. package/dist/agent/report.d.ts +0 -3
  19. package/dist/agent/report.d.ts.map +0 -1
  20. package/dist/agent/report.js +0 -107
  21. package/dist/agent/report.js.map +0 -1
  22. package/dist/browser/executor.d.ts +0 -5
  23. package/dist/browser/executor.d.ts.map +0 -1
  24. package/dist/browser/executor.js +0 -87
  25. package/dist/browser/executor.js.map +0 -1
  26. package/dist/browser/pool.d.ts +0 -33
  27. package/dist/browser/pool.d.ts.map +0 -1
  28. package/dist/browser/pool.js +0 -101
  29. package/dist/browser/pool.js.map +0 -1
  30. package/dist/browser/snapshot.d.ts +0 -7
  31. package/dist/browser/snapshot.d.ts.map +0 -1
  32. package/dist/browser/snapshot.js +0 -201
  33. package/dist/browser/snapshot.js.map +0 -1
  34. package/dist/config/defaults.d.ts +0 -17
  35. package/dist/config/defaults.d.ts.map +0 -1
  36. package/dist/config/defaults.js +0 -17
  37. package/dist/config/defaults.js.map +0 -1
  38. package/dist/config/schema.d.ts +0 -169
  39. package/dist/config/schema.d.ts.map +0 -1
  40. package/dist/config/schema.js +0 -53
  41. package/dist/config/schema.js.map +0 -1
  42. package/dist/index.d.ts +0 -9
  43. package/dist/index.d.ts.map +0 -1
  44. package/dist/index.js +0 -10
  45. package/dist/index.js.map +0 -1
  46. package/dist/llm/client.d.ts +0 -23
  47. package/dist/llm/client.d.ts.map +0 -1
  48. package/dist/llm/client.js +0 -88
  49. package/dist/llm/client.js.map +0 -1
  50. package/dist/llm/prompt.d.ts +0 -15
  51. package/dist/llm/prompt.d.ts.map +0 -1
  52. package/dist/llm/prompt.js +0 -82
  53. package/dist/llm/prompt.js.map +0 -1
  54. package/dist/llm/vision-models.d.ts +0 -3
  55. package/dist/llm/vision-models.d.ts.map +0 -1
  56. package/dist/llm/vision-models.js +0 -30
  57. package/dist/llm/vision-models.js.map +0 -1
  58. package/dist/scraper/extractors/content.d.ts +0 -33
  59. package/dist/scraper/extractors/content.d.ts.map +0 -1
  60. package/dist/scraper/extractors/content.js +0 -276
  61. package/dist/scraper/extractors/content.js.map +0 -1
  62. package/dist/scraper/extractors/ssr.d.ts +0 -18
  63. package/dist/scraper/extractors/ssr.d.ts.map +0 -1
  64. package/dist/scraper/extractors/ssr.js +0 -162
  65. package/dist/scraper/extractors/ssr.js.map +0 -1
  66. package/dist/scraper/extractors/to-markdown.d.ts +0 -5
  67. package/dist/scraper/extractors/to-markdown.d.ts.map +0 -1
  68. package/dist/scraper/extractors/to-markdown.js +0 -103
  69. package/dist/scraper/extractors/to-markdown.js.map +0 -1
  70. package/dist/scraper/index.d.ts +0 -35
  71. package/dist/scraper/index.d.ts.map +0 -1
  72. package/dist/scraper/index.js +0 -299
  73. package/dist/scraper/index.js.map +0 -1
  74. package/dist/scraper/tiers/tier1-http.d.ts +0 -5
  75. package/dist/scraper/tiers/tier1-http.d.ts.map +0 -1
  76. package/dist/scraper/tiers/tier1-http.js +0 -116
  77. package/dist/scraper/tiers/tier1-http.js.map +0 -1
  78. package/dist/scraper/tiers/tier2-stealth.d.ts +0 -5
  79. package/dist/scraper/tiers/tier2-stealth.d.ts.map +0 -1
  80. package/dist/scraper/tiers/tier2-stealth.js +0 -109
  81. package/dist/scraper/tiers/tier2-stealth.js.map +0 -1
  82. package/dist/scraper/tiers/tier3-browser.d.ts +0 -11
  83. package/dist/scraper/tiers/tier3-browser.d.ts.map +0 -1
  84. package/dist/scraper/tiers/tier3-browser.js +0 -511
  85. package/dist/scraper/tiers/tier3-browser.js.map +0 -1
  86. package/dist/scraper/types.d.ts +0 -161
  87. package/dist/scraper/types.d.ts.map +0 -1
  88. package/dist/scraper/types.js +0 -3
  89. package/dist/scraper/types.js.map +0 -1
  90. package/dist/security/action-validator.d.ts +0 -98
  91. package/dist/security/action-validator.d.ts.map +0 -1
  92. package/dist/security/action-validator.js +0 -72
  93. package/dist/security/action-validator.js.map +0 -1
  94. package/dist/security/url-validator.d.ts +0 -9
  95. package/dist/security/url-validator.d.ts.map +0 -1
  96. package/dist/security/url-validator.js +0 -78
  97. package/dist/security/url-validator.js.map +0 -1
  98. package/dist/types.d.ts +0 -168
  99. package/dist/types.d.ts.map +0 -1
  100. package/dist/types.js +0 -2
  101. package/dist/types.js.map +0 -1
@@ -1,511 +0,0 @@
1
- import { chromium } from "playwright";
2
- import { extractContent } from "../extractors/content.js";
3
- import { htmlToMarkdown } from "../extractors/to-markdown.js";
4
- // ─── Tier 3: Playwright Chromium (fallback final) ──────────────────────────
5
- //
6
- // Acionado quando Tier 1 (HTTP) e Tier 2 (Stealth HTTP) falham.
7
- // Casos típicos: SPAs complexas, anti-bot pesado (Cloudflare, Akamai, etc.).
8
- //
9
- // Estratégias aplicadas:
10
- // 1. Stealth scripts injetados antes de qualquer script da página
11
- // 2. Interceptar chamadas de API JSON (melhor para SPAs — dados diretos)
12
- // 3. Bloquear recursos desnecessários (fonts, media, analytics)
13
- // 4. Aguardar networkidle ou seletor específico
14
- // 5. Extrair DOM completo e converter para Markdown
15
- // ──────────────────────────────────────────────────────────────────────────
16
- // User-Agent de Chrome real para Windows (OS mais comum = menos suspeito).
17
- // Atualizar a cada 2-3 versões major do Chrome.
18
- const CHROME_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36";
19
- // Args que reduzem sinais de automação detectáveis
20
- const STEALTH_ARGS = [
21
- "--disable-blink-features=AutomationControlled",
22
- "--disable-features=IsolateOrigins,site-per-process",
23
- "--disable-infobars",
24
- "--no-first-run",
25
- "--no-sandbox",
26
- "--disable-setuid-sandbox",
27
- "--disable-dev-shm-usage",
28
- "--disable-accelerated-2d-canvas",
29
- "--no-zygote",
30
- "--disable-gpu",
31
- "--window-size=1920,1080",
32
- "--disable-background-networking",
33
- "--disable-client-side-phishing-detection",
34
- "--disable-component-update",
35
- "--disable-default-apps",
36
- "--disable-domain-reliability",
37
- "--disable-extensions",
38
- "--disable-hang-monitor",
39
- "--disable-popup-blocking",
40
- "--disable-prompt-on-repost",
41
- "--disable-sync",
42
- "--metrics-recording-only",
43
- "--safebrowsing-disable-auto-update",
44
- ];
45
- // ─── Script de anti-detecção (injetado antes de qualquer JS da página) ────────
46
- //
47
- // Cobre as principais técnicas usadas por anti-bots modernos
48
- // (Cloudflare, DataDome, Akamai, PerimeterX, Shape Security):
49
- //
50
- // 1. navigator.webdriver → remove o flag mais óbvio
51
- // 2. navigator.plugins → simula os 3 plugins reais do Chrome
52
- // 3. Propriedades de hardware → concurrency, memory, maxTouchPoints, vendor, platform
53
- // 4. window.chrome → objeto completo (runtime, loadTimes, csi, app)
54
- // 5. Notification.permission → 'default' (headless retorna 'denied')
55
- // 6. Permission API → 'prompt' para notifications
56
- // 7. Canvas fingerprint → ruído de 1 bit no toDataURL (quebra fingerprinting)
57
- // 8. WebGL UNMASKED_VENDOR/RENDERER → GPU Intel realista (em vez de llvmpipe/SwiftShader)
58
- // 9. Screen.colorDepth/pixelDepth → 24 bits
59
- // 10. Remoção de artefatos → remove vars de outras ferramentas (Selenium, PhantomJS)
60
- // ──────────────────────────────────────────────────────────────────────────────
61
- const STEALTH_INIT_SCRIPT = /* language=javascript */ `
62
- (function () {
63
- // ── 1. Remove a flag mais básica de automação ─────────────────────────
64
- Object.defineProperty(navigator, 'webdriver', {
65
- get: () => undefined,
66
- configurable: true,
67
- });
68
-
69
- // ── 2. Plugins realistas de um Chrome normal ──────────────────────────
70
- // navigator.plugins.length === 0 é o maior red-flag de headless.
71
- const makeMime = (type, suffixes, desc, plugin) => {
72
- const mt = Object.create(MimeType.prototype);
73
- Object.defineProperties(mt, {
74
- type: { value: type, enumerable: true },
75
- suffixes: { value: suffixes, enumerable: true },
76
- description: { value: desc, enumerable: true },
77
- enabledPlugin: { value: plugin, enumerable: true },
78
- });
79
- return mt;
80
- };
81
-
82
- const makePlugin = (name, desc, filename, mimeSpecs) => {
83
- const p = Object.create(Plugin.prototype);
84
- Object.defineProperties(p, {
85
- name: { value: name, enumerable: true },
86
- description: { value: desc, enumerable: true },
87
- filename: { value: filename, enumerable: true },
88
- length: { value: mimeSpecs.length },
89
- });
90
- mimeSpecs.forEach((spec, i) => {
91
- const mt = makeMime(spec.type, spec.suffixes, spec.desc, p);
92
- Object.defineProperty(p, i, { value: mt, enumerable: true });
93
- Object.defineProperty(p, spec.type, { value: mt });
94
- });
95
- p.item = (i) => p[i] ?? null;
96
- p.namedItem = (n) => p[n] ?? null;
97
- return p;
98
- };
99
-
100
- const pdfViewer = makePlugin(
101
- 'PDF Viewer', 'Portable Document Format', 'internal-pdf-viewer',
102
- [
103
- { type: 'application/pdf', suffixes: 'pdf', desc: '' },
104
- { type: 'text/pdf', suffixes: 'pdf', desc: '' },
105
- ],
106
- );
107
- const chromePDF = makePlugin(
108
- 'Chrome PDF Viewer', '', 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
109
- [{ type: 'application/pdf', suffixes: 'pdf', desc: '' }],
110
- );
111
- const nacl = makePlugin(
112
- 'Native Client', '', 'internal-nacl-plugin',
113
- [
114
- { type: 'application/x-nacl', suffixes: '', desc: 'Native Client Executable' },
115
- { type: 'application/x-pnacl', suffixes: '', desc: 'Portable Native Client Executable' },
116
- ],
117
- );
118
-
119
- const pluginList = [pdfViewer, chromePDF, nacl];
120
- const pa = Object.create(PluginArray.prototype);
121
- Object.defineProperty(pa, 'length', { value: pluginList.length });
122
- pluginList.forEach((plug, i) => {
123
- Object.defineProperty(pa, i, { value: plug, enumerable: true });
124
- Object.defineProperty(pa, plug.name, { value: plug });
125
- });
126
- pa.item = (i) => pluginList[i] ?? null;
127
- pa.namedItem = (n) => pa[n] ?? null;
128
- pa.refresh = () => {};
129
-
130
- Object.defineProperty(navigator, 'plugins', { get: () => pa });
131
-
132
- // ── 3. Propriedades de hardware realistas ─────────────────────────────
133
- Object.defineProperty(navigator, 'languages', { get: () => ['pt-BR', 'pt', 'en-US', 'en'] });
134
- Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });
135
- Object.defineProperty(navigator, 'deviceMemory', { get: () => 8 });
136
- Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0 });
137
- Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.' });
138
- Object.defineProperty(navigator, 'platform', { get: () => 'Win32' });
139
-
140
- // ── 4. window.chrome — objeto completo como Chrome real ──────────────
141
- // Automação headless deixa window.chrome undefined ou com .runtime vazio.
142
- if (!window.chrome) window.chrome = {};
143
-
144
- if (!window.chrome.app) {
145
- window.chrome.app = {
146
- isInstalled: false,
147
- getDetails: () => null,
148
- getIsInstalled: () => false,
149
- InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
150
- RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },
151
- };
152
- }
153
-
154
- if (!window.chrome.runtime) {
155
- window.chrome.runtime = {
156
- id: undefined,
157
- connect: () => { throw Object.assign(new Error('Could not establish connection.'), { message: 'Could not establish connection. Receiving end does not exist.' }); },
158
- sendMessage: () => { throw Object.assign(new Error('Could not establish connection.'), { message: 'Could not establish connection. Receiving end does not exist.' }); },
159
- PlatformOs: { MAC: 'mac', WIN: 'win', ANDROID: 'android', CROS: 'cros', LINUX: 'linux', OPENBSD: 'openbsd' },
160
- PlatformArch: { ARM: 'arm', ARM64: 'arm64', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
161
- };
162
- }
163
-
164
- if (!window.chrome.loadTimes) {
165
- window.chrome.loadTimes = () => {
166
- const now = Date.now() / 1000;
167
- return {
168
- requestTime: now - 1.5 - Math.random() * 0.5,
169
- startLoadTime: now - 1.2 - Math.random() * 0.3,
170
- commitLoadTime: now - 0.8 - Math.random() * 0.2,
171
- finishDocumentLoadTime: now - 0.3 - Math.random() * 0.1,
172
- finishLoadTime: now - 0.1 - Math.random() * 0.05,
173
- firstPaintTime: now - 0.9 - Math.random() * 0.2,
174
- firstPaintAfterLoadTime: now - 0.05,
175
- navigationType: 'Other',
176
- wasFetchedViaSpdy: true,
177
- wasNpnNegotiated: true,
178
- npnNegotiatedProtocol: 'h2',
179
- wasAlternateProtocolAvailable: false,
180
- connectionInfo: 'h2',
181
- };
182
- };
183
- }
184
-
185
- if (!window.chrome.csi) {
186
- window.chrome.csi = () => ({
187
- startE: Date.now() - 1000,
188
- onloadT: Date.now(),
189
- pageT: 500 + Math.random() * 1000,
190
- tran: 15,
191
- });
192
- }
193
-
194
- // ── 5. Notification API — headless retorna 'denied', real retorna 'default' ─
195
- try {
196
- if (typeof Notification !== 'undefined') {
197
- Object.defineProperty(Notification, 'permission', { get: () => 'default' });
198
- }
199
- } catch (_) {}
200
-
201
- // ── 6. Permission API — 'notifications' deve retornar 'prompt' ────────
202
- if (navigator.permissions) {
203
- const origQuery = navigator.permissions.query.bind(navigator.permissions);
204
- navigator.permissions.query = (params) => {
205
- if (params && params.name === 'notifications') {
206
- return Promise.resolve({ state: 'prompt', onchange: null, addEventListener: () => {}, removeEventListener: () => {}, dispatchEvent: () => true });
207
- }
208
- return origQuery(params);
209
- };
210
- }
211
-
212
- // ── 7. Canvas fingerprint — ruído sutil no último byte do dataURL ─────
213
- // Técnica: altera 1 bit → output diferente em cada run → quebra fingerprinting.
214
- // Impacto visual: imperceptível (altera apenas o encoding base64 do último pixel).
215
- const _origToDataURL = HTMLCanvasElement.prototype.toDataURL;
216
- HTMLCanvasElement.prototype.toDataURL = function (type, quality) {
217
- const data = _origToDataURL.call(this, type, quality);
218
- if (data.length < 12) return data;
219
- const idx = data.length - 2;
220
- return data.slice(0, idx) + String.fromCharCode(data.charCodeAt(idx) ^ 0x01) + data.slice(idx + 1);
221
- };
222
-
223
- // ── 8. WebGL — GPU Intel realista em vez de llvmpipe/SwiftShader ─────
224
- // llvmpipe/SwiftShader = fingerprint de VM detectado por todos os anti-bots.
225
- const WEBGL_VENDOR = 'Google Inc. (Intel)';
226
- const WEBGL_RENDERER = 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)';
227
-
228
- const patchWebGL = (Ctx) => {
229
- if (!Ctx) return;
230
- const orig = Ctx.prototype.getParameter;
231
- Ctx.prototype.getParameter = function (param) {
232
- if (param === 37445) return WEBGL_VENDOR; // UNMASKED_VENDOR_WEBGL
233
- if (param === 37446) return WEBGL_RENDERER; // UNMASKED_RENDERER_WEBGL
234
- return orig.call(this, param);
235
- };
236
- };
237
-
238
- patchWebGL(typeof WebGLRenderingContext !== 'undefined' ? WebGLRenderingContext : null);
239
- patchWebGL(typeof WebGL2RenderingContext !== 'undefined' ? WebGL2RenderingContext : null);
240
-
241
- // ── 9. Screen depth realista ──────────────────────────────────────────
242
- try {
243
- Object.defineProperty(screen, 'colorDepth', { get: () => 24 });
244
- Object.defineProperty(screen, 'pixelDepth', { get: () => 24 });
245
- } catch (_) {}
246
-
247
- // ── 10. Remove artefatos de outras ferramentas de automação ──────────
248
- const automationVars = ['__nightmare', '_phantom', 'callPhantom',
249
- '__selenium_evaluate', '__webdriver_evaluate', '_Selenium_IDE_Recorder',
250
- '__webdriver_script_fn', '__lastWatirAlert', '__lastWatirConfirm'];
251
- automationVars.forEach(v => { try { delete window[v]; } catch (_) {} });
252
-
253
- })();
254
- `;
255
- // Recursos que bloqueamos para economizar banda/tempo.
256
- // "image" incluído: extraímos texto/markdown, não renderizamos visualmente.
257
- const BLOCKED_RESOURCE_TYPES = new Set(["font", "media", "image"]);
258
- // Padrões de analytics/rastreamento a bloquear
259
- const BLOCKED_URL_PATTERNS = [
260
- "google-analytics.com",
261
- "googletagmanager.com",
262
- "facebook.net/en_US/fbevents.js",
263
- "connect.facebook.net",
264
- "hotjar.com",
265
- "fullstory.com",
266
- "segment.com",
267
- "mixpanel.com",
268
- "amplitude.com",
269
- "sentry.io",
270
- "clarity.ms",
271
- "doubleclick.net",
272
- "adnxs.com",
273
- "criteo.com",
274
- "taboola.com",
275
- "outbrain.com",
276
- ];
277
- export class Tier3Browser {
278
- browser = null;
279
- browserPromise = null;
280
- browserConfig;
281
- constructor(browserConfig = {}) {
282
- this.browserConfig = browserConfig;
283
- }
284
- // ── Lifecycle do browser (singleton with mutex) ────────────────────────
285
- async getBrowser() {
286
- if (this.browser?.isConnected())
287
- return this.browser;
288
- if (!this.browserPromise) {
289
- this.browserPromise = (async () => {
290
- const launchOptions = {
291
- headless: this.browserConfig.headless ?? true,
292
- args: STEALTH_ARGS,
293
- };
294
- if (this.browserConfig.executablePath) {
295
- launchOptions.executablePath = this.browserConfig.executablePath;
296
- }
297
- else if (this.browserConfig.channel) {
298
- launchOptions.channel = this.browserConfig.channel;
299
- }
300
- else {
301
- try {
302
- const browser = await chromium.launch({ ...launchOptions, channel: "chrome" });
303
- this.browser = browser;
304
- this.browserPromise = null;
305
- return browser;
306
- }
307
- catch {
308
- // Chrome not found → use Playwright's bundled Chromium
309
- }
310
- }
311
- const browser = await chromium.launch(launchOptions);
312
- this.browser = browser;
313
- this.browserPromise = null;
314
- return browser;
315
- })();
316
- }
317
- return this.browserPromise;
318
- }
319
- // ── Scraping principal ─────────────────────────────────────────────────
320
- async scrape(url, options = {}) {
321
- const startTime = Date.now();
322
- const browser = await this.getBrowser();
323
- let context = null;
324
- try {
325
- context = await browser.newContext({
326
- userAgent: CHROME_UA,
327
- viewport: { width: 1920, height: 1080 },
328
- locale: "pt-BR",
329
- timezoneId: "America/Sao_Paulo",
330
- extraHTTPHeaders: {
331
- "accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
332
- ...(options.headers ?? {}),
333
- },
334
- javaScriptEnabled: true,
335
- // Desabilita WebRTC para evitar vazamento de IP real em ambientes com proxy
336
- // (equivalente a --disable-webrtc nos args, mas via context)
337
- });
338
- const page = await context.newPage();
339
- // ── Injetar stealth script ANTES de qualquer script da página ─────
340
- await page.addInitScript(STEALTH_INIT_SCRIPT);
341
- // ── Bloquear recursos desnecessários ──────────────────────────────
342
- await page.route("**/*", (route) => {
343
- const req = route.request();
344
- const type = req.resourceType();
345
- const reqUrl = req.url();
346
- if (BLOCKED_RESOURCE_TYPES.has(type)) {
347
- return route.abort();
348
- }
349
- if (type === "script" &&
350
- BLOCKED_URL_PATTERNS.some((p) => reqUrl.includes(p))) {
351
- return route.abort();
352
- }
353
- return route.continue();
354
- });
355
- // ── Interceptação de APIs JSON (fundamental para SPAs) ────────────
356
- const interceptedAPIs = [];
357
- const shouldIntercept = options.interceptAPIs !== false;
358
- if (shouldIntercept) {
359
- page.on("response", async (response) => {
360
- try {
361
- const contentType = response.headers()["content-type"] ?? "";
362
- if (!contentType.includes("application/json"))
363
- return;
364
- const apiUrl = response.url();
365
- // Ignora analytics e recursos JS/CSS
366
- if (BLOCKED_URL_PATTERNS.some((p) => apiUrl.includes(p)))
367
- return;
368
- if (/\.(js|css|png|jpg|gif|svg|woff)/.test(apiUrl))
369
- return;
370
- // Ignora respostas muito grandes (provavelmente não são dados da view)
371
- const contentLength = parseInt(response.headers()["content-length"] ?? "0", 10);
372
- if (contentLength > 500_000)
373
- return;
374
- const data = await response.json().catch(() => null);
375
- if (!data)
376
- return;
377
- interceptedAPIs.push({
378
- url: apiUrl,
379
- method: response.request().method(),
380
- statusCode: response.status(),
381
- contentType,
382
- data,
383
- });
384
- }
385
- catch {
386
- // Resposta já consumida ou parse inválido — ignora silenciosamente
387
- }
388
- });
389
- }
390
- // Auto-dismiss dialogs (alert/confirm/prompt) para não travar a navegação
391
- page.on("dialog", (dialog) => dialog.dismiss().catch(() => { }));
392
- // ── Navegação com retry ────────────────────────────────────────────
393
- // Em sites com anti-bot, a 1ª tentativa pode receber um challenge (403/503).
394
- // A 2ª tentativa (com cookies/state acumulados) frequentemente passa.
395
- const timeout = options.timeout ?? 30_000;
396
- let statusCode = 200;
397
- let lastNavError = null;
398
- for (let attempt = 1; attempt <= 2; attempt++) {
399
- try {
400
- const navResponse = await page.goto(url, {
401
- waitUntil: "domcontentloaded",
402
- timeout: Math.min(timeout, 30_000),
403
- });
404
- statusCode = navResponse?.status() ?? 200;
405
- lastNavError = null;
406
- break; // Sucesso — sai do loop
407
- }
408
- catch (navErr) {
409
- lastNavError = navErr instanceof Error ? navErr : new Error(String(navErr));
410
- if (attempt < 2) {
411
- await page.waitForTimeout(1_500).catch(() => { });
412
- }
413
- }
414
- }
415
- if (lastNavError) {
416
- throw new Error(`Tier3 Browser: falha na navegação — ${lastNavError.message}`);
417
- }
418
- // ── Aguardar conteúdo dinâmico ────────────────────────────────────
419
- // networkidle sinaliza que a SPA terminou de carregar
420
- await page
421
- .waitForLoadState("networkidle", {
422
- timeout: Math.min(timeout * 0.5, 15_000),
423
- })
424
- .catch(() => {
425
- // Timeout é aceitável — prosseguimos com o que tiver
426
- });
427
- // Seletor específico do usuário (ex: '.product-list', '#app')
428
- if (options.waitForSelector) {
429
- await page
430
- .waitForSelector(options.waitForSelector, {
431
- state: "visible",
432
- timeout: 10_000,
433
- })
434
- .catch(() => {
435
- // Seletor não apareceu — prosseguimos assim mesmo
436
- });
437
- }
438
- // ── Scroll para ativar lazy-loading ───────────────────────────────
439
- // Muitos sites usam IntersectionObserver para carregar conteúdo apenas
440
- // quando o usuário rola até ele. Varrer a página simula esse comportamento
441
- // e garante que todo o conteúdo seja carregado antes da extração.
442
- await page
443
- .evaluate(() => {
444
- return new Promise((resolve) => {
445
- const totalHeight = document.body.scrollHeight;
446
- if (totalHeight <= window.innerHeight) {
447
- resolve();
448
- return;
449
- }
450
- const step = Math.max(Math.floor(totalHeight / 6), 300);
451
- let scrolled = 0;
452
- const tick = () => {
453
- scrolled += step;
454
- window.scrollTo({ top: scrolled, behavior: "smooth" });
455
- if (scrolled < totalHeight) {
456
- // Intervalo variado simula comportamento humano e dá tempo ao
457
- // IntersectionObserver disparar e buscar conteúdo novo
458
- setTimeout(tick, 120 + Math.floor(Math.random() * 130));
459
- }
460
- else {
461
- window.scrollTo({ top: 0, behavior: "instant" });
462
- resolve();
463
- }
464
- };
465
- setTimeout(tick, 400);
466
- });
467
- })
468
- .catch(() => {
469
- // Scroll falhou (página sem body ou JS bloqueado) — ignora
470
- });
471
- // ── Extração de conteúdo ──────────────────────────────────────────
472
- const [html, pageTitle] = await Promise.all([
473
- page.content(),
474
- page.title(),
475
- ]);
476
- const finalUrl = page.url();
477
- const formats = options.formats ?? ["markdown", "text"];
478
- const extracted = extractContent(html, options.onlyMainContent ?? true, finalUrl);
479
- const result = {
480
- url: finalUrl,
481
- statusCode,
482
- title: pageTitle || extracted.title,
483
- description: extracted.description || undefined,
484
- tier: "browser",
485
- durationMs: Date.now() - startTime,
486
- links: extracted.links.length > 0 ? extracted.links : undefined,
487
- interceptedAPIs: interceptedAPIs.length > 0 ? interceptedAPIs : undefined,
488
- };
489
- if (options.getRawHtml)
490
- result.rawHtml = html;
491
- if (formats.includes("markdown"))
492
- result.markdown = htmlToMarkdown(extracted.html);
493
- if (formats.includes("html"))
494
- result.html = extracted.html;
495
- if (formats.includes("text"))
496
- result.text = extracted.text;
497
- return result;
498
- }
499
- finally {
500
- await context?.close().catch(() => { });
501
- }
502
- }
503
- // ── Encerrar browser ───────────────────────────────────────────────────
504
- async close() {
505
- if (this.browser) {
506
- await this.browser.close().catch(() => { });
507
- this.browser = null;
508
- }
509
- }
510
- }
511
- //# sourceMappingURL=tier3-browser.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tier3-browser.js","sourceRoot":"","sources":["../../../src/scraper/tiers/tier3-browser.ts"],"names":[],"mappings":"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"}