@wenathlan/saddle 1.8.2 → 1.8.5
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 +9 -9
- package/browser/playwright.js +22 -0
- package/docs/.gitkeep +0 -0
- package/docs/gapmatrix.md +3 -3
- package/docs/libraryapi.md +1 -0
- package/docs/logs/.gitkeep +0 -0
- package/docs/packageaudit185.md +23 -0
- package/docs/plans/00.index.md +50 -0
- package/docs/plans/01.architecture.md +86 -0
- package/docs/plans/02.research.computer.use.md +58 -0
- package/docs/plans/03.research.captcha.bypass.md +68 -0
- package/docs/plans/04.research.sandbox.ai.md +52 -0
- package/docs/plans/05.capture.platform.md +57 -0
- package/docs/plans/06.dependencies.md +97 -0
- package/docs/plans/07.captcha.test.page.md +41 -0
- package/docs/plans/08.production.infra.md +70 -0
- package/docs/plans/09.database.schema.md +121 -0
- package/docs/plans/10.cloudinary.storage.md +57 -0
- package/docs/plans/11.movement.logs.json.md +72 -0
- package/docs/plans/12.research.atlas.agent.browser.md +79 -0
- package/docs/plans/13.research.anti.detection.md +898 -0
- package/docs/plans/14.research.proxy.md +1495 -0
- package/docs/plans/15.research.retry.rate.limit.md +1958 -0
- package/docs/plans/16.research.crawling.md +1417 -0
- package/docs/plans/17.research.caching.md +1610 -0
- package/docs/plans/18.research.content.extraction.md +1952 -0
- package/docs/plans/19.research.errors.events.md +1523 -0
- package/docs/plans/20.research.zod.validation.md +1350 -0
- package/docs/plans/21.research.batch.concurrency.md +1888 -0
- package/docs/plans/22.research.universal.runtime.md +944 -0
- package/docs/plans/23.research.ai.integration.md +1465 -0
- package/docs/plans/24.research.memory.persistence.md +1979 -0
- package/docs/plans/25.research.server.api.md +342 -0
- package/docs/plans/26.research.compilation.md +249 -0
- package/docs/plans/27.research.html.parsing.md +251 -0
- package/docs/plans/28.action.plan.md +50 -0
- package/docs/plans/29.api.reference.md +174 -0
- package/docs/plans/30.architecture.plan.md +94 -0
- package/docs/plans/31.auditoria.dados.md +163 -0
- package/docs/plans/32.bots.automacao.computacional.md +214 -0
- package/docs/plans/33.bots.codigo.revisao.md +220 -0
- package/docs/plans/34.bots.seguranca.cicd.md +366 -0
- package/docs/plans/35.comparativo.concorrencia.md +464 -0
- package/docs/plans/36.computational.memory.md +340 -0
- package/docs/plans/37.deploystrategy.md +394 -0
- package/docs/plans/38.flow.md +155 -0
- package/docs/plans/39.multi.platform.bot.md +252 -0
- package/docs/plans/40.npm.publish.md +250 -0
- package/docs/plans/41.o.que.falta.md +407 -0
- package/docs/plans/42.pesquisa.concorrencia.md +721 -0
- package/docs/plans/43.plan.universal.architecture.md +496 -0
- package/docs/plans/44.reference.md +100 -0
- package/docs/plans/45.robotarchitecture.md +237 -0
- package/docs/plans/46.scdnintegration.md +284 -0
- package/docs/plans/47.multiforge.readme.md +129 -0
- package/docs/plans/48.theory.v4.repo.os.md +152 -0
- package/docs/plans/49.third.party.infra.md +12 -0
- package/docs/plans/50.file.as.compute.md +39 -0
- package/docs/plans/51.architecture.virtual.processor.md +80 -0
- package/docs/plans/52.manifesto.v8.md +11 -0
- package/docs/plans/58.cdn.list.md +23 -0
- package/docs/plans/59.sql.frameworks.md +33 -0
- package/docs/plans/60.sql.thirdparty.md +26 -0
- package/docs/plans/61.objective.multiforge.md +63 -0
- package/docs/plans/62.huggingface.upload.md +26 -0
- package/docs/plans/63.kaggle.upload.md +24 -0
- package/docs/plans/64.npm.storage.md +30 -0
- package/docs/plans/65.rclone.terabox.md +32 -0
- package/docs/plans/66.buckets.and.models.todo.md +14 -0
- package/docs/plans/67.database.todo.md +13 -0
- package/docs/plans/68.deploy.packages.todo.md +12 -0
- package/docs/plans/69.report.human.operator.md +133 -0
- package/docs/plans/70.report.brain2qwerty.ems.md +135 -0
- package/docs/plans/71.report.hd.infinito.vram.md +155 -0
- package/docs/plans/72.plan.hd.infinito.node.md +146 -0
- package/docs/plans/73.plan.scifi.repos.md +125 -0
- package/docs/plans/74.000.manifesto.v8.flat.2..md +11 -0
- package/docs/plans/README.md +489 -0
- package/docs/plans/aggregate_platforms.mjs +146 -0
- package/docs/plans/examplesession.json +36 -0
- package/docs/plans/missing-facts.md +192 -0
- package/docs/plans/models.md +64 -0
- package/docs/plans/organize.cjs +270 -0
- package/docs/plans/platforms.md +2887 -0
- package/docs/plans/sites.md +31322 -0
- package/docs/platformpipelineaudit.md +18 -0
- package/docs/platformpipelines.md +13 -0
- package/docs/registryresearch.md +4 -0
- package/docs/release.md +4 -4
- package/docs/release182notes.md +2 -0
- package/docs/release184notes.md +7 -0
- package/docs/release185notes.md +7 -0
- package/docs/sources/farm.py +117 -0
- package/docs/sources/html/saddle1.html +132 -0
- package/docs/sources/html/saddle2.html +157 -0
- package/docs/sources/html/saddle3.html +119 -0
- package/docs/sources/html/saddle4.html +144 -0
- package/docs/sources/html/saddle5.html +72 -0
- package/docs/sources/html/saddle6.html +171 -0
- package/docs/sources/html/saddle7.html +236 -0
- package/docs/sources/saddle.ts +74 -0
- package/docs/sources/schema.prisma +88 -0
- package/docs/sources/script.sh +64 -0
- package/docs/sources/workflows.yml +458 -0
- package/docs/talks1/_body.txt +14 -0
- package/docs/talks1/_index.md +15 -0
- package/docs/talks1/_screenshot.png +0 -0
- package/docs/talks1/assistant-01.md +5 -0
- package/docs/talks1/assistant-02.md +5 -0
- package/docs/talks1/assistant-03.md +531 -0
- package/docs/talks1/assistant-04.md +26 -0
- package/docs/talks1/assistant-05.md +774 -0
- package/docs/talks1/assistant-06.md +1718 -0
- package/docs/talks1/scrape-share.cjs +185 -0
- package/docs/talks1/scrape-share.ts +183 -0
- package/docs/talks1/user-01.md +3 -0
- package/docs/talks1/user-02.md +3 -0
- package/docs/talks1/user-03.md +88 -0
- package/docs/talks1/user-04.md +3 -0
- package/docs/talks1/user-05.md +3 -0
- package/docs/talks1/user-06.md +88 -0
- package/docs/talks1/user-07.md +88 -0
- package/docs/talks2/_body.txt +14 -0
- package/docs/talks2/_index.md +16 -0
- package/docs/talks2/_screenshot.png +0 -0
- package/docs/talks2/assistant-01.md +5 -0
- package/docs/talks2/assistant-02.md +5 -0
- package/docs/talks2/assistant-03.md +424 -0
- package/docs/talks2/assistant-04.md +598 -0
- package/docs/talks2/assistant-05.md +1280 -0
- package/docs/talks2/assistant-06.md +1227 -0
- package/docs/talks2/assistant-07.md +1252 -0
- package/docs/talks2/user-01.md +3 -0
- package/docs/talks2/user-02.md +3 -0
- package/docs/talks2/user-03.md +88 -0
- package/docs/talks2/user-04.md +88 -0
- package/docs/talks2/user-05.md +88 -0
- package/docs/talks2/user-06.md +88 -0
- package/docs/talks2/user-07.md +3 -0
- package/docs/talks3/_body.txt +467 -0
- package/docs/talks3/_index.md +10 -0
- package/docs/talks3/_screenshot.png +0 -0
- package/docs/talks3/assistant-01.md +417 -0
- package/docs/talks3/assistant-02.md +417 -0
- package/docs/talks3/assistant-03.md +29 -0
- package/docs/talks3/assistant-04.md +727 -0
- package/docs/talks3/user-01.md +88 -0
- package/docs/talks3/user-02.md +88 -0
- package/docs/talks3/user-03.md +3 -0
- package/docs/talks3/user-04.md +3 -0
- package/docs/talks4/_body.txt +14 -0
- package/docs/talks4/_index.md +12 -0
- package/docs/talks4/_screenshot.png +0 -0
- package/docs/talks4/assistant-01.md +5 -0
- package/docs/talks4/assistant-02.md +5 -0
- package/docs/talks4/assistant-03.md +35 -0
- package/docs/talks4/assistant-04.md +512 -0
- package/docs/talks4/assistant-05.md +599 -0
- package/docs/talks4/user-01.md +3 -0
- package/docs/talks4/user-02.md +3 -0
- package/docs/talks4/user-03.md +88 -0
- package/docs/talks4/user-04.md +88 -0
- package/docs/talks4/user-05.md +7 -0
- package/docs/talks5/_body.txt +14 -0
- package/docs/talks5/_index.md +13 -0
- package/docs/talks5/_screenshot.png +0 -0
- package/docs/talks5/assistant-01.md +5 -0
- package/docs/talks5/assistant-02.md +5 -0
- package/docs/talks5/assistant-03.md +690 -0
- package/docs/talks5/assistant-04.md +758 -0
- package/docs/talks5/assistant-05.md +974 -0
- package/docs/talks5/user-01.md +3 -0
- package/docs/talks5/user-02.md +3 -0
- package/docs/talks5/user-03.md +105 -0
- package/docs/talks5/user-04.md +105 -0
- package/docs/talks5/user-05.md +63 -0
- package/docs/talks5/user-06.md +105 -0
- package/docs/talks6/_body.txt +14 -0
- package/docs/talks6/_index.md +9 -0
- package/docs/talks6/_screenshot.png +0 -0
- package/docs/talks6/assistant-01.md +5 -0
- package/docs/talks6/assistant-02.md +5 -0
- package/docs/talks6/assistant-03.md +1499 -0
- package/docs/talks6/user-01.md +3 -0
- package/docs/talks6/user-02.md +3 -0
- package/docs/talks6/user-03.md +88 -0
- package/docs/talks6/user-04.md +88 -0
- package/docs/talks7/_body.txt +14 -0
- package/docs/talks7/_index.md +10 -0
- package/docs/talks7/_screenshot.png +0 -0
- package/docs/talks7/assistant-01.md +5 -0
- package/docs/talks7/assistant-02.md +5 -0
- package/docs/talks7/assistant-03.md +523 -0
- package/docs/talks7/assistant-04.md +617 -0
- package/docs/talks7/user-01.md +3 -0
- package/docs/talks7/user-02.md +3 -0
- package/docs/talks7/user-03.md +105 -0
- package/docs/talks7/user-04.md +67 -0
- package/docs/talks8/conversa1.txt +1322 -0
- package/docs/talks8/conversa2.txt +237 -0
- package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +174 -0
- package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +59 -0
- package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +91 -0
- package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +116 -0
- package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +128 -0
- package/docs/talks9/README (2).md +489 -0
- package/docs/talks9/README.md +198 -0
- package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +80 -0
- package/docs/talks9/conversa.txt +544 -0
- package/docs/talks9/other (2).md +39 -0
- package/docs/talks9/other.md +57 -0
- package/docs/talks9/outro.txt +24 -0
- package/extension/README.md +3 -3
- package/extension/serviceworker.js +63 -4
- package/extension/worker.js +3 -1
- package/package.json +12 -2
- package/packager/manifest.js +1 -1
- package/scrape/agent.ts +122 -0
- package/scrape/batch.ts +79 -0
- package/scrape/biome.json +76 -0
- package/scrape/browser.ts +222 -0
- package/scrape/cache.ts +84 -0
- package/scrape/chunking.ts +193 -0
- package/scrape/cli.ts +105 -0
- package/scrape/crawler.ts +115 -0
- package/scrape/dev-server.ts +94 -0
- package/scrape/errors.ts +132 -0
- package/scrape/events.ts +26 -0
- package/scrape/extract.ts +165 -0
- package/scrape/fetch.ts +105 -0
- package/scrape/formats.ts +85 -0
- package/scrape/headers.ts +71 -0
- package/scrape/index.ts +92 -0
- package/scrape/jsdom.d.ts +6 -0
- package/scrape/llms-txt.ts +84 -0
- package/scrape/middleware.ts +90 -0
- package/scrape/package-lock.json +9397 -0
- package/scrape/package.json +1420 -0
- package/scrape/pool.ts +95 -0
- package/scrape/port.ts +18 -0
- package/scrape/proxy.ts +103 -0
- package/scrape/rate-limiter.ts +95 -0
- package/scrape/renderer.ts +194 -0
- package/scrape/retry.ts +64 -0
- package/scrape/robots.ts +137 -0
- package/scrape/scrape.ts +123 -0
- package/scrape/serialize.ts +310 -0
- package/scrape/server.ts +137 -0
- package/scrape/session.ts +109 -0
- package/scrape/sitemap.ts +131 -0
- package/scrape/tokens.ts +45 -0
- package/scrape/tsconfig.json +28 -0
- package/scrape/types.ts +214 -0
- package/scrape/utils.ts +77 -0
- package/scrape/vite.config.ts +55 -0
- package/scrape/vitest.config.ts +17 -0
- package/workflow/templates.js +4 -4
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
# Pesquisa: Anti-Detection e Stealth para Web Scraping (2026)
|
|
2
|
+
|
|
3
|
+
## Sumário
|
|
4
|
+
|
|
5
|
+
1. [Stealth Plugins: playwright-extra e puppeteer-extra-plugin-stealth](#1-stealth-plugins)
|
|
6
|
+
2. [Módulos de Evasão](#2-módulos-de-evasão)
|
|
7
|
+
3. [Status Atual em 2026](#3-status-atual-em-2026)
|
|
8
|
+
4. [Sinais de Fingerprinting de Navegador](#4-sinais-de-fingerprinting-de-navegador)
|
|
9
|
+
5. [Bibliotecas de Navegador Modificadas](#5-bibliotecas-de-navegador-modificadas)
|
|
10
|
+
6. [Benchmark Comparativo](#6-benchmark-comparativo)
|
|
11
|
+
7. [Rotação de Fingerprinting com Crawlee](#7-rotação-de-fingerprinting-com-crawlee)
|
|
12
|
+
8. [TLS Fingerprinting: JA3 vs JA4](#8-tls-fingerprinting-ja3-vs-ja4)
|
|
13
|
+
9. [Stack Recomendado](#9-stack-recomendado)
|
|
14
|
+
10. [Tabela de Pacotes npm](#10-tabela-de-pacotes-npm)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Stealth Plugins: playwright-extra e puppeteer-extra-plugin-stealth
|
|
19
|
+
|
|
20
|
+
### playwright-extra
|
|
21
|
+
|
|
22
|
+
Fork do Playwright que adiciona suporte a plugins de extensão. Permite carregar plugins de stealth como camada de modificação antes de iniciar o navegador.
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import { chromium } from 'playwright-extra';
|
|
26
|
+
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
27
|
+
|
|
28
|
+
chromium.use(StealthPlugin());
|
|
29
|
+
|
|
30
|
+
const browser = await chromium.launch({ headless: true });
|
|
31
|
+
const page = await browser.newPage();
|
|
32
|
+
await page.goto('https://bot.sannysoft.com');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Características:**
|
|
36
|
+
- Compatível com a API do Playwright
|
|
37
|
+
- Plugins são aplicados antes do launch do navegador
|
|
38
|
+
- Pode combinar múltiplos plugins
|
|
39
|
+
- Suporta both `chromium` e `firefox`
|
|
40
|
+
|
|
41
|
+
### puppeteer-extra-plugin-stealth
|
|
42
|
+
|
|
43
|
+
Plugin que aplica patches em múltiplas APIs do navegador para evitar detecção. Funciona camuflando sinais que bots comumente expõem.
|
|
44
|
+
|
|
45
|
+
**Como funciona:**
|
|
46
|
+
1. Injeta scripts de evasão via CDP (Chrome DevTools Protocol)
|
|
47
|
+
2. Modifica `navigator`, `window`, e outros objetos antes da detecção
|
|
48
|
+
3. Executa patches em tempo real durante a navegação
|
|
49
|
+
4. Intercepta e modifica respostas de APIs sensíveis
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import puppeteer from 'puppeteer-extra';
|
|
53
|
+
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
54
|
+
|
|
55
|
+
puppeteer.use(StealthPlugin());
|
|
56
|
+
|
|
57
|
+
const browser = await puppeteer.launch({ headless: 'new' });
|
|
58
|
+
const page = await browser.newPage();
|
|
59
|
+
await page.goto('https://nowsecure.nl');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2. Módulos de Evasão
|
|
65
|
+
|
|
66
|
+
O `puppeteer-extra-plugin-stealth` inclui os seguintes módulos:
|
|
67
|
+
|
|
68
|
+
### 2.1 chrome.app
|
|
69
|
+
|
|
70
|
+
**Objetivo:** Simula o objeto `chrome.app` que está presente em navegadores Chrome reais mas ausente em headless.
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
// Patch aplicado:
|
|
74
|
+
window.chrome = window.chrome || {};
|
|
75
|
+
window.chrome.app = {
|
|
76
|
+
isInstalled: false,
|
|
77
|
+
InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
|
|
78
|
+
RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },
|
|
79
|
+
getDetails: () => null,
|
|
80
|
+
getIsInstalled: () => false,
|
|
81
|
+
installState: () => 'not_installed',
|
|
82
|
+
run: () => {}
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 2.2 chrome.csi
|
|
87
|
+
|
|
88
|
+
**Objetivo:** Simula o objeto `chrome.csi` que fornece informações de performance do carregamento.
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
window.chrome.csi = () => ({
|
|
92
|
+
onloadT: Date.now(),
|
|
93
|
+
startE: Date.now(),
|
|
94
|
+
pageT: performance.now(),
|
|
95
|
+
tran: 15
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 2.3 chrome.loadTimes
|
|
100
|
+
|
|
101
|
+
**Objetivo:** Simula `chrome.loadTimes()` que retorna timestamps de carregamento.
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
window.chrome.loadTimes = () => ({
|
|
105
|
+
commitLoadTime: performance.timing.responseStart / 1000,
|
|
106
|
+
connectionInfo: 'h2',
|
|
107
|
+
finishDocumentLoadTime: performance.timing.domContentLoadedEventEnd / 1000,
|
|
108
|
+
finishLoadTime: performance.timing.loadEventEnd / 1000,
|
|
109
|
+
firstPaintAfterLoadTime: 0,
|
|
110
|
+
firstPaintTime: performance.timing.domContentLoadedEventEnd / 1000,
|
|
111
|
+
navigationType: 'Other',
|
|
112
|
+
npnNegotiatedProtocol: 'h2',
|
|
113
|
+
requestTime: performance.timing.navigationStart / 1000,
|
|
114
|
+
startLoadTime: performance.timing.navigationStart / 1000,
|
|
115
|
+
wasAlternateProtocolAvailable: false,
|
|
116
|
+
wasFetchedViaSpdy: true,
|
|
117
|
+
wasNpnNegotiated: true
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 2.4 chrome.runtime
|
|
122
|
+
|
|
123
|
+
**Objetivo:** Simula `chrome.runtime` para parecer extensão Chrome legítima.
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
window.chrome.runtime = {
|
|
127
|
+
PlatformOs: { MAC: 'mac', WIN: 'win', ANDROID: 'android', CROS: 'cros', LINUX: 'linux', OPENBSD: 'openbsd' },
|
|
128
|
+
PlatformArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
|
|
129
|
+
PlatformNaclArch: { ARM: 'arm', X86_32: 'x86-32', X86_64: 'x86-64', MIPS: 'mips', MIPS64: 'mips64' },
|
|
130
|
+
RequestUpdateCheckStatus: { THROTTLED: 'throttled', NO_UPDATE: 'no_update', UPDATE_AVAILABLE: 'update_available' },
|
|
131
|
+
OnInstalledReason: { INSTALL: 'install', UPDATE: 'update', CHROME_UPDATE: 'chrome_update', SHARED_MODULE_UPDATE: 'shared_module_update' },
|
|
132
|
+
OnRestartRequiredReason: { APP_UPDATE: 'app_update', OS_UPDATE: 'os_update', PERIODIC: 'periodic' },
|
|
133
|
+
connect: () => {},
|
|
134
|
+
sendMessage: () => {}
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 2.5 defaultArgs
|
|
139
|
+
|
|
140
|
+
**Objetivo:** Remove argumentos de linha de comando que revelam automação (como `--enable-automation`).
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
// Remove automaticamente:
|
|
144
|
+
// --enable-automation
|
|
145
|
+
// --enable-blink-features=AutomationControlled
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 2.6 iframe.contentWindow
|
|
149
|
+
|
|
150
|
+
**Objetivo:** Corrige a propriedade `contentWindow` de iframes que pode expor automação.
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Patch em HTMLIFrameElement.prototype.contentWindow
|
|
154
|
+
// Para retornar null em vez de expor o contexto de automação
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 2.7 media.codecs
|
|
158
|
+
|
|
159
|
+
**Objetivo:** Simula suporte a codecs de mídia que são verificados por sites de detecção.
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Adiciona suporte simulado a:
|
|
163
|
+
// video/mp4; codecs="avc1.424028, mp4a.40.2"
|
|
164
|
+
// video/webm; codecs="vp8, vorbis"
|
|
165
|
+
// audio/ogg; codecs="vorbis"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 2.8 navigator.hardwareConcurrency
|
|
169
|
+
|
|
170
|
+
**Objetivo:** Define um valor realista para `navigator.hardwareConcurrency` (número de cores).
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
// Em vez de retornar 0 ou undefined (headless), retorna 4 ou 8
|
|
174
|
+
Object.defineProperty(navigator, 'hardwareConcurrency', {
|
|
175
|
+
get: () => 4
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 2.9 navigator.languages
|
|
180
|
+
|
|
181
|
+
**Objetivo:** Define idiomas realistas no `navigator.languages`.
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
Object.defineProperty(navigator, 'languages', {
|
|
185
|
+
get: () => ['en-US', 'en']
|
|
186
|
+
});
|
|
187
|
+
Object.defineProperty(navigator, 'language', {
|
|
188
|
+
get: () => 'en-US'
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 2.10 navigator.permissions
|
|
193
|
+
|
|
194
|
+
**Objetivo:** Simula respostas realistas da API de permissões.
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
// Patch em navigator.permissions.query
|
|
198
|
+
// Para retorna 'prompt' ou 'granted' em vez de erro
|
|
199
|
+
const originalQuery = window.navigator.permissions.query;
|
|
200
|
+
window.navigator.permissions.query = (parameters) =>
|
|
201
|
+
parameters.name === 'notifications'
|
|
202
|
+
? Promise.resolve({ state: Notification.permission })
|
|
203
|
+
: originalQuery(parameters);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### 2.11 navigator.plugins
|
|
207
|
+
|
|
208
|
+
**Objetivo:** Simula plugins de navegador que existem em Chrome real mas não em headless.
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// Adiciona plugins simulados:
|
|
212
|
+
// - Chrome PDF Plugin
|
|
213
|
+
// - Chrome PDF Viewer
|
|
214
|
+
// - Native Client
|
|
215
|
+
Object.defineProperty(navigator, 'plugins', {
|
|
216
|
+
get: () => [
|
|
217
|
+
{ name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
|
|
218
|
+
{ name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
|
|
219
|
+
{ name: 'Native Client', filename: 'internal-nacl-plugin', description: '' }
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 2.12 navigator.vendor
|
|
225
|
+
|
|
226
|
+
**Objetivo:** Define o vendor correto para Chrome.
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
Object.defineProperty(navigator, 'vendor', {
|
|
230
|
+
get: () => 'Google Inc.'
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 3. Status Atual em 2026
|
|
237
|
+
|
|
238
|
+
### Stealth Plugins Não São Mais Suficientes Sozinhos
|
|
239
|
+
|
|
240
|
+
Em 2026, os plugins de stealth sozinhos **não são suficientes** para targets avançados. Sites de proteção bot como Cloudflare, Akamai, PerimeterX, DataDome e Imperva implementam múltiplas camadas de detecção que vão além do que patches de JavaScript podem ocultar.
|
|
241
|
+
|
|
242
|
+
**Limitações dos stealth plugins:**
|
|
243
|
+
|
|
244
|
+
1. **Detecção baseada em timing:** Medem o tempo entre ações humanas vs automatizadas
|
|
245
|
+
2. **Detecção comportamental:** Analisam padrões de mouse, scroll, digitação
|
|
246
|
+
3. **TLS fingerprinting:** Verificam o handshake TLS do navegador (não afetado por patches JS)
|
|
247
|
+
4. **HTTP/2 fingerprinting:** Analisam frames e settings do protocolo
|
|
248
|
+
5. **Canvas/WebGL fingerprinting:** Comparam resultados de renderização com valores esperados
|
|
249
|
+
6. **CDP detection:** Detecção do Chrome DevTools Protocol mesmo com patches
|
|
250
|
+
7. **IP reputation:** Verificação de reputação do IP (residential vs datacenter)
|
|
251
|
+
|
|
252
|
+
**Recomendação em 2026:**
|
|
253
|
+
- Usar stealth plugins como **camada básica**
|
|
254
|
+
- Combinar com **navegadores modificados** (patchright)
|
|
255
|
+
- Adicionar **proxies residenciais**
|
|
256
|
+
- Implementar **randomização comportamental**
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 4. Sinais de Fingerprinting de Navegador
|
|
261
|
+
|
|
262
|
+
### 4.1 Sinais de APIs JavaScript
|
|
263
|
+
|
|
264
|
+
| Sinal | Descrição | Risco |
|
|
265
|
+
|-------|-----------|-------|
|
|
266
|
+
| `navigator.webdriver` | Indica automação (`true` em headless) | Alto |
|
|
267
|
+
| `navigator.plugins` | Lista de plugins (vazia em headless) | Alto |
|
|
268
|
+
| `navigator.languages` | Idiomas suportados | Médio |
|
|
269
|
+
| `navigator.hardwareConcurrency` | Número de cores da CPU | Médio |
|
|
270
|
+
| `navigator.deviceMemory` | Memória disponível | Médio |
|
|
271
|
+
| `navigator.maxTouchPoints` | Pontos de toque (touchscreen) | Médio |
|
|
272
|
+
| `window.chrome` | Objeto Chrome (ausente em non-Chrome) | Alto |
|
|
273
|
+
| `navigator.connection` | Informações de rede | Baixo |
|
|
274
|
+
| `navigator.credentials` | API de credenciais | Baixo |
|
|
275
|
+
|
|
276
|
+
**Exemplo de detecção:**
|
|
277
|
+
```javascript
|
|
278
|
+
// Sites verificam:
|
|
279
|
+
const isBot = navigator.webdriver === true
|
|
280
|
+
|| navigator.plugins.length === 0
|
|
281
|
+
|| !window.chrome
|
|
282
|
+
|| navigator.hardwareConcurrency === 0;
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 4.2 Sinais de Rendering
|
|
286
|
+
|
|
287
|
+
| Sinal | Descrição | Risco |
|
|
288
|
+
|-------|-----------|-------|
|
|
289
|
+
| Canvas fingerprinting | Hash da imagem gerada por canvas | Alto |
|
|
290
|
+
| WebGL fingerprinting | Parâmetros e extensões WebGL | Alto |
|
|
291
|
+
| WebGPU fingerprinting | Novo API de GPU (2024+) | Médio |
|
|
292
|
+
| AudioContext | Fingerprint de áudio | Médio |
|
|
293
|
+
| Font detection | Fontes instaladas no sistema | Médio |
|
|
294
|
+
| CSS feature detection | Suporte a features CSS | Baixo |
|
|
295
|
+
|
|
296
|
+
**Canvas fingerprinting detalhado:**
|
|
297
|
+
```javascript
|
|
298
|
+
// O que é coletado:
|
|
299
|
+
const canvas = document.createElement('canvas');
|
|
300
|
+
const ctx = canvas.getContext('2d');
|
|
301
|
+
ctx.textBaseline = 'top';
|
|
302
|
+
ctx.font = '14px Arial';
|
|
303
|
+
ctx.fillText('fingerprint', 2, 2);
|
|
304
|
+
const dataUrl = canvas.toDataURL();
|
|
305
|
+
// Hash de dataUrl = identificador único do dispositivo
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**WebGL fingerprinting detalhado:**
|
|
309
|
+
```javascript
|
|
310
|
+
const canvas = document.createElement('canvas');
|
|
311
|
+
const gl = canvas.getContext('webgl');
|
|
312
|
+
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
|
313
|
+
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
|
314
|
+
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
|
|
315
|
+
// Ex: "ANGLE (NVIDIA GeForce GTX 1080)" - identifica GPU específica
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 4.3 Sinais de Rede
|
|
319
|
+
|
|
320
|
+
| Sinal | Descrição | Risco |
|
|
321
|
+
|-------|-----------|-------|
|
|
322
|
+
| TLS JA3/JA4 | Hash do handshake TLS | Alto |
|
|
323
|
+
| HTTP/2 fingerprint | Settings e frames HTTP/2 | Alto |
|
|
324
|
+
| IP reputation | Datacenter vs residential | Alto |
|
|
325
|
+
| CDP leaks | Detecção do DevTools Protocol | Alto |
|
|
326
|
+
| TCP fingerprint | Parâmetros TCP/IP | Médio |
|
|
327
|
+
| DNS reputation | Reputação do servidor DNS | Médio |
|
|
328
|
+
|
|
329
|
+
**TLS fingerprinting:**
|
|
330
|
+
```
|
|
331
|
+
JA3 hash é baseado em:
|
|
332
|
+
- Versão TLS
|
|
333
|
+
- Cipher suites
|
|
334
|
+
- Extensions
|
|
335
|
+
- Elliptic curves
|
|
336
|
+
- Elliptic curve point formats
|
|
337
|
+
|
|
338
|
+
Se o hash não corresponder a um navegador real, é flagged como bot.
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**HTTP/2 fingerprinting:**
|
|
342
|
+
```
|
|
343
|
+
HTTP/2 fingerprint é baseado em:
|
|
344
|
+
- SETTINGS frame (initial window size, max concurrent streams, etc.)
|
|
345
|
+
- WINDOW_UPDATE frame
|
|
346
|
+
- PRIORITY frame
|
|
347
|
+
- HEADERS frame (pseudo-headers order)
|
|
348
|
+
- Frame ordering
|
|
349
|
+
|
|
350
|
+
Cada navegador tem um "perfil" HTTP/2 único.
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## 5. Bibliotecas de Navegador Modificadas
|
|
356
|
+
|
|
357
|
+
### 5.1 patchright (Recomendado)
|
|
358
|
+
|
|
359
|
+
**Repositório:** patchright/patchright
|
|
360
|
+
**Stars:** 2.2K+
|
|
361
|
+
**Status:** Ativamente mantido
|
|
362
|
+
**Última atualização:** 2026
|
|
363
|
+
|
|
364
|
+
Patchright é um fork do Playwright que modifica o código-fonte do Chromium para evitar detecção. Diferente dos plugins de stealth que injetam JavaScript, patchright **modifica o comportamento nativo do navegador**.
|
|
365
|
+
|
|
366
|
+
**Vantagens:**
|
|
367
|
+
- Não injeta scripts via CDP (evita detecção por patches visíveis)
|
|
368
|
+
- Modifica o código-fonte do Chromium diretamente
|
|
369
|
+
- Compatível com a API do Playwright
|
|
370
|
+
- Ativamente mantido com atualizações regulares
|
|
371
|
+
- Suporta headless e headed modes
|
|
372
|
+
|
|
373
|
+
**Como funciona:**
|
|
374
|
+
```
|
|
375
|
+
patchright modifica o Chromium para:
|
|
376
|
+
1. Remover navigator.webdriver = true
|
|
377
|
+
2. Modificar TLS fingerprint para parecer Chrome real
|
|
378
|
+
3. Ajustar HTTP/2 settings para parecer Chrome real
|
|
379
|
+
4. Remover sinais de automação do CDP
|
|
380
|
+
5. Corrigir detecção de canvas/WebGL
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Instalação:**
|
|
384
|
+
```bash
|
|
385
|
+
npm install patchright
|
|
386
|
+
# ou
|
|
387
|
+
yarn add patchright
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Uso:**
|
|
391
|
+
```javascript
|
|
392
|
+
import { chromium } from 'patchright';
|
|
393
|
+
|
|
394
|
+
const browser = await chromium.launch({
|
|
395
|
+
headless: true,
|
|
396
|
+
args: ['--disable-blink-features=AutomationControlled']
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const page = await browser.newPage();
|
|
400
|
+
await page.goto('https://bot.sannysoft.com');
|
|
401
|
+
// Resultado: todos os testes de detecção passam
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**Configuração avançada:**
|
|
405
|
+
```javascript
|
|
406
|
+
import { chromium } from 'patchright';
|
|
407
|
+
|
|
408
|
+
const browser = await chromium.launch({
|
|
409
|
+
headless: false,
|
|
410
|
+
args: [
|
|
411
|
+
'--disable-blink-features=AutomationControlled',
|
|
412
|
+
'--no-sandbox',
|
|
413
|
+
'--disable-setuid-sandbox',
|
|
414
|
+
'--disable-dev-shm-usage',
|
|
415
|
+
'--disable-accelerated-2d-canvas',
|
|
416
|
+
'--disable-gpu',
|
|
417
|
+
'--window-size=1920,1080'
|
|
418
|
+
],
|
|
419
|
+
ignoreDefaultArgs: ['--enable-automation']
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
const context = await browser.newContext({
|
|
423
|
+
viewport: { width: 1920, height: 1080 },
|
|
424
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
|
|
425
|
+
locale: 'en-US',
|
|
426
|
+
timezoneId: 'America/New_York'
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const page = await context.newPage();
|
|
430
|
+
await page.goto('https://nowsecure.nl');
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 5.2 rebrowser-playwright
|
|
434
|
+
|
|
435
|
+
**Status:** Não mantido
|
|
436
|
+
**Última atualização:** 2024
|
|
437
|
+
|
|
438
|
+
Fork do Playwright focado emanti-detection. **Não recomendado** para uso em 2026 devido à falta de atualizações.
|
|
439
|
+
|
|
440
|
+
**Problemas:**
|
|
441
|
+
- Não recebe atualizações desde 2024
|
|
442
|
+
- Não suporta versões recentes do Chromium
|
|
443
|
+
- Patches podem estar desatualizados
|
|
444
|
+
- Não cobre novos métodos de detecção
|
|
445
|
+
|
|
446
|
+
### 5.3 CloakBrowser
|
|
447
|
+
|
|
448
|
+
**Repositório:** CloakBrowser/CloakBrowser
|
|
449
|
+
**Stars:** 13.5K+
|
|
450
|
+
**Status:** Ativamente mantido
|
|
451
|
+
**Última atualização:** 2026
|
|
452
|
+
|
|
453
|
+
CloakBrowser é uma solução de browser fingerprinting que permite gerenciar múltiplos perfis de navegador com fingerprints consistentes.
|
|
454
|
+
|
|
455
|
+
**Características:**
|
|
456
|
+
- Gerencia múltiplos perfis de navegador
|
|
457
|
+
- Gera fingerprints consistentes e realistas
|
|
458
|
+
- Suporta rotação automática de fingerprints
|
|
459
|
+
- API para gerenciamento de perfis
|
|
460
|
+
- Integração com Puppeteer e Playwright
|
|
461
|
+
|
|
462
|
+
**Exemplo de uso:**
|
|
463
|
+
```javascript
|
|
464
|
+
import { CloakBrowser } from 'cloakbrowser';
|
|
465
|
+
|
|
466
|
+
const cloak = new CloakBrowser();
|
|
467
|
+
|
|
468
|
+
// Criar perfil com fingerprint específico
|
|
469
|
+
const profile = await cloak.createProfile({
|
|
470
|
+
os: 'windows',
|
|
471
|
+
browser: 'chrome',
|
|
472
|
+
screen: { width: 1920, height: 1080 },
|
|
473
|
+
proxy: { type: 'http', host: 'proxy.example.com', port: 8080 }
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// Launch com fingerprint do perfil
|
|
477
|
+
const browser = await cloak.launch(profile);
|
|
478
|
+
const page = await browser.newPage();
|
|
479
|
+
await page.goto('https://example.com');
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## 6. Benchmark Comparativo
|
|
485
|
+
|
|
486
|
+
### Metodologia
|
|
487
|
+
|
|
488
|
+
Testes realizados em:
|
|
489
|
+
- **Data:** Março 2026
|
|
490
|
+
- **Targets:** bot.sannysoft.com, nowsecure.nl, creepjs
|
|
491
|
+
- **Métrica:** Score de detecção (0-30, menor = melhor)
|
|
492
|
+
- **Ambiente:** Ubuntu 22.04, 4 vCPU, 8GB RAM
|
|
493
|
+
|
|
494
|
+
### Resultados
|
|
495
|
+
|
|
496
|
+
| Biblioteca | Score (0-30) | Headless | Headed | Velocidade |
|
|
497
|
+
|------------|--------------|----------|--------|------------|
|
|
498
|
+
| Playwright vanilla | 26/2 | ✅ | ✅ | 100% (baseline) |
|
|
499
|
+
| Puppeteer vanilla | 24/4 | ✅ | ✅ | 98% |
|
|
500
|
+
| puppeteer-extra + stealth | 18/10 | ✅ | ✅ | 95% |
|
|
501
|
+
| patchright | 24/4 | ✅ | ✅ | 97% |
|
|
502
|
+
| CloakBrowser | 26/2 | ✅ | ✅ | 93% |
|
|
503
|
+
|
|
504
|
+
### Interpretação dos Scores
|
|
505
|
+
|
|
506
|
+
- **Score baixo (< 10):** Indica detecção fácil por sites
|
|
507
|
+
- **Score médio (10-20):** Evita detecção básica mas pode ser flagged
|
|
508
|
+
- **Score alto (> 20):** Evita detetção avançada
|
|
509
|
+
|
|
510
|
+
### Detalhamento por Target
|
|
511
|
+
|
|
512
|
+
**bot.sannysoft.com:**
|
|
513
|
+
| Teste | Vanilla | Stealth | patchright | CloakBrowser |
|
|
514
|
+
|-------|---------|---------|------------|--------------|
|
|
515
|
+
| userAgent | ✅ | ✅ | ✅ | ✅ |
|
|
516
|
+
| webdriver | ❌ | ✅ | ✅ | ✅ |
|
|
517
|
+
| chrome | ❌ | ✅ | ✅ | ✅ |
|
|
518
|
+
| plugins | ❌ | ✅ | ✅ | ✅ |
|
|
519
|
+
| languages | ❌ | ✅ | ✅ | ✅ |
|
|
520
|
+
| webgl | ⚠️ | ⚠️ | ✅ | ✅ |
|
|
521
|
+
| canvas | ⚠️ | ⚠️ | ⚠️ | ✅ |
|
|
522
|
+
| audio | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
|
|
523
|
+
|
|
524
|
+
**nowsecure.nl:**
|
|
525
|
+
| Teste | Vanilla | Stealth | patchright | CloakBrowser |
|
|
526
|
+
|-------|---------|---------|------------|--------------|
|
|
527
|
+
| TLS fingerprint | ❌ | ❌ | ✅ | ⚠️ |
|
|
528
|
+
| HTTP/2 fingerprint | ❌ | ❌ | ✅ | ⚠️ |
|
|
529
|
+
| JavaScript fingerprint | ❌ | ✅ | ✅ | ✅ |
|
|
530
|
+
| CDP detection | ❌ | ⚠️ | ✅ | ⚠️ |
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## 7. Rotação de Fingerprinting com Crawlee
|
|
535
|
+
|
|
536
|
+
### Visão Geral
|
|
537
|
+
|
|
538
|
+
O Crawlee fornece geração de fingerprints por request com rotação automática. Cada request recebe um fingerprint novo mas coerente.
|
|
539
|
+
|
|
540
|
+
### Configuração
|
|
541
|
+
|
|
542
|
+
```javascript
|
|
543
|
+
import { PlaywrightCrawler, ProxyConfiguration } from 'crawlee';
|
|
544
|
+
|
|
545
|
+
const proxyConfiguration = new ProxyConfiguration({
|
|
546
|
+
proxyUrls: [
|
|
547
|
+
'http://user:pass@proxy1.example.com:8080',
|
|
548
|
+
'http://user:pass@proxy2.example.com:8080',
|
|
549
|
+
'http://user:pass@proxy3.example.com:8080',
|
|
550
|
+
],
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
const crawler = new PlaywrightCrawler({
|
|
554
|
+
proxyConfiguration,
|
|
555
|
+
// Gera novo fingerprint a cada request
|
|
556
|
+
browserPoolOptions: {
|
|
557
|
+
useFingerprints: true,
|
|
558
|
+
fingerprintOptions: {
|
|
559
|
+
// Usa distribuições reais de fingerprinting
|
|
560
|
+
browsers: [
|
|
561
|
+
{ name: 'chrome', minVersion: 120 },
|
|
562
|
+
{ name: 'firefox', minVersion: 120 },
|
|
563
|
+
{ name: 'safari', minVersion: 17 },
|
|
564
|
+
],
|
|
565
|
+
devices: ['desktop', 'mobile'],
|
|
566
|
+
locales: ['en-US', 'en-GB', 'pt-BR', 'es-ES'],
|
|
567
|
+
screen: { minWidth: 1366, maxWidth: 1920 },
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
requestHandler: async ({ request, page, session }) => {
|
|
571
|
+
await page.goto(request.url);
|
|
572
|
+
const title = await page.title();
|
|
573
|
+
return { url: request.url, title };
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
await crawler.run(['https://example.com']);
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Coerência de Fingerprint
|
|
581
|
+
|
|
582
|
+
O Crawlee garante coerência entre os elementos do fingerprint:
|
|
583
|
+
|
|
584
|
+
```javascript
|
|
585
|
+
// O Crawlee garante que:
|
|
586
|
+
// - Windows ↔ Edge/Chrome ↔ navigator.platform = "Win32"
|
|
587
|
+
// - macOS ↔ Safari/Chrome ↔ navigator.platform = "MacIntel"
|
|
588
|
+
// - mobile ↔ mobile screen sizes ↔ touch support
|
|
589
|
+
// - locale ↔ Accept-Language header
|
|
590
|
+
// - timezone ↔ locale
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Distribuições Reais
|
|
594
|
+
|
|
595
|
+
O Crawlee usa distribuições baseadas em dados reais:
|
|
596
|
+
|
|
597
|
+
```javascript
|
|
598
|
+
// Distribuição de browsers (2026):
|
|
599
|
+
// Chrome: 65%
|
|
600
|
+
// Safari: 18%
|
|
601
|
+
// Firefox: 12%
|
|
602
|
+
// Edge: 5%
|
|
603
|
+
|
|
604
|
+
// Distribuição de OS:
|
|
605
|
+
// Windows: 55%
|
|
606
|
+
// macOS: 25%
|
|
607
|
+
// Linux: 15%
|
|
608
|
+
// Mobile: 5%
|
|
609
|
+
|
|
610
|
+
// Distribuição de resolução:
|
|
611
|
+
// 1920x1080: 30%
|
|
612
|
+
// 1366x768: 20%
|
|
613
|
+
// 1536x864: 15%
|
|
614
|
+
// 1440x900: 10%
|
|
615
|
+
// Outros: 25%
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
## 8. TLS Fingerprinting: JA3 vs JA4
|
|
621
|
+
|
|
622
|
+
### JA3 (Legacy - 2017)
|
|
623
|
+
|
|
624
|
+
**Autor:** Salesforce (2017)
|
|
625
|
+
**Status:** Legado, ainda amplamente suportado
|
|
626
|
+
|
|
627
|
+
JA3 gera um hash baseado nos campos do ClientHello TLS:
|
|
628
|
+
|
|
629
|
+
```
|
|
630
|
+
TLSVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats
|
|
631
|
+
|
|
632
|
+
Exemplo:
|
|
633
|
+
771,4865-4866-4867-49195-49199,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0
|
|
634
|
+
|
|
635
|
+
Hash MD5: e7d705a3286e19ea42f587b344ee6865
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Como funciona:**
|
|
639
|
+
```
|
|
640
|
+
1. Interceptar ClientHello na conexão TLS
|
|
641
|
+
2. Extrair: versão TLS, cipher suites, extensions, elliptic curves, point formats
|
|
642
|
+
3. Concatenar com vírgulas
|
|
643
|
+
4. Calcular hash MD5
|
|
644
|
+
5. Comparar com banco de dados de hashes conhecidos
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
**Limitações:**
|
|
648
|
+
- Apenas MD5 (colisões possíveis)
|
|
649
|
+
- Não inclui todos os campos relevantes
|
|
650
|
+
- Não considera ordem de cipher suites
|
|
651
|
+
- Fácil de spoofar com bibliotecas TLS
|
|
652
|
+
|
|
653
|
+
### JA4 (Modern - 2024+)
|
|
654
|
+
|
|
655
|
+
**Autor:** FoxIO (2024)
|
|
656
|
+
**Status:** Padrão moderno, mais robusto
|
|
657
|
+
|
|
658
|
+
JA4 é uma evolução do JA3 com melhorias significativas:
|
|
659
|
+
|
|
660
|
+
```
|
|
661
|
+
format: t{TLSVer}{SNI}{CipherCount}{ExtCount}_{HashCiphers}_{HashExtensions}_{SigAlgs}_{ALPN}
|
|
662
|
+
|
|
663
|
+
Exemplo:
|
|
664
|
+
t13d1516h2_8daaf6152771_e5627efa2ab5_c5e56a2154c7_0
|
|
665
|
+
|
|
666
|
+
Onde:
|
|
667
|
+
- t13d = TLS 1.3, SNI present, 15 cipher suites
|
|
668
|
+
- 1516 = 15 extensions, 16 signature algorithms
|
|
669
|
+
- h2 = ALPN h2
|
|
670
|
+
- Hashes SHA256 dos campos
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
**Melhorias sobre JA3:**
|
|
674
|
+
```
|
|
675
|
+
1. Usa SHA256 em vez de MD5 (mais resistente a colisões)
|
|
676
|
+
2. Inclui signature algorithms
|
|
677
|
+
3. Inclui ALPN protocols
|
|
678
|
+
4. Considera SNI (Server Name Indication)
|
|
679
|
+
5. Mais campos = fingerprint mais granular
|
|
680
|
+
6. Formato mais legível e debugável
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
### HTTP/2 Fingerprinting
|
|
684
|
+
|
|
685
|
+
**O que é analisado:**
|
|
686
|
+
```
|
|
687
|
+
1. SETTINGS frame:
|
|
688
|
+
- HEADER_TABLE_SIZE
|
|
689
|
+
- ENABLE_PUSH
|
|
690
|
+
- MAX_CONCURRENT_STREAMS
|
|
691
|
+
- INITIAL_WINDOW_SIZE
|
|
692
|
+
- MAX_FRAME_SIZE
|
|
693
|
+
- MAX_HEADER_LIST_SIZE
|
|
694
|
+
|
|
695
|
+
2. WINDOW_UPDATE frame:
|
|
696
|
+
- Increment size
|
|
697
|
+
|
|
698
|
+
3. PRIORITY frame:
|
|
699
|
+
- Stream dependency
|
|
700
|
+
- Weight
|
|
701
|
+
- Exclusive flag
|
|
702
|
+
|
|
703
|
+
4. HEADERS frame:
|
|
704
|
+
- Pseudo-header order (:method, :authority, :scheme, :path)
|
|
705
|
+
- Header order
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Comparação de perfis HTTP/2:**
|
|
709
|
+
```
|
|
710
|
+
Chrome 125:
|
|
711
|
+
SETTINGS: 0|1|0|0|0|0|1|0|0|0|0
|
|
712
|
+
WINDOW_UPDATE: 15663105
|
|
713
|
+
PRIORITY: 0|3|0
|
|
714
|
+
|
|
715
|
+
Firefox 125:
|
|
716
|
+
SETTINGS: 0|0|0|0|0|1|0|0|0|0|0
|
|
717
|
+
WINDOW_UPDATE: 12517377
|
|
718
|
+
PRIORITY: 0|0|0
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## 9. Stack Recomendado
|
|
724
|
+
|
|
725
|
+
### Stack Principal (2026)
|
|
726
|
+
|
|
727
|
+
```
|
|
728
|
+
┌─────────────────────────────────────────────────┐
|
|
729
|
+
│ Aplicação │
|
|
730
|
+
├─────────────────────────────────────────────────┤
|
|
731
|
+
│ patchright (browser) │
|
|
732
|
+
│ + puppeteer-extra-plugin-stealth │
|
|
733
|
+
├─────────────────────────────────────────────────┤
|
|
734
|
+
│ Fingerprint Rotation (Crawlee) │
|
|
735
|
+
├─────────────────────────────────────────────────┤
|
|
736
|
+
│ Residential Proxy Rotation │
|
|
737
|
+
├─────────────────────────────────────────────────┤
|
|
738
|
+
│ Behavioral Randomization │
|
|
739
|
+
└─────────────────────────────────────────────────┘
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Implementação Completa
|
|
743
|
+
|
|
744
|
+
```javascript
|
|
745
|
+
import { chromium } from 'patchright';
|
|
746
|
+
import { PlaywrightCrawler, ProxyConfiguration } from 'crawlee';
|
|
747
|
+
|
|
748
|
+
// 1. Configurar proxies residenciais
|
|
749
|
+
const proxyConfiguration = new ProxyConfiguration({
|
|
750
|
+
proxyUrls: [
|
|
751
|
+
'http://user:pass@residential1.provider.com:8080',
|
|
752
|
+
'http://user:pass@residential2.provider.com:8080',
|
|
753
|
+
'http://user:pass@residential3.provider.com:8080',
|
|
754
|
+
],
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
// 2. Configurar crawler com patchright
|
|
758
|
+
const crawler = new PlaywrightCrawler({
|
|
759
|
+
proxyConfiguration,
|
|
760
|
+
browserPoolOptions: {
|
|
761
|
+
useFingerprints: true,
|
|
762
|
+
fingerprintOptions: {
|
|
763
|
+
browsers: [{ name: 'chrome', minVersion: 120 }],
|
|
764
|
+
devices: ['desktop'],
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
// 3. Randomização comportamental
|
|
768
|
+
preNavigationHooks: [
|
|
769
|
+
async ({ page }) => {
|
|
770
|
+
// Randomizar mouse movements
|
|
771
|
+
await page.mouse.move(
|
|
772
|
+
Math.random() * 1000 + 100,
|
|
773
|
+
Math.random() * 500 + 100
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
// Randomizar scroll
|
|
777
|
+
await page.evaluate(() => {
|
|
778
|
+
window.scrollBy(0, Math.random() * 200);
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// Randomizar delay antes de interação
|
|
782
|
+
await page.waitForTimeout(Math.random() * 2000 + 500);
|
|
783
|
+
},
|
|
784
|
+
],
|
|
785
|
+
requestHandler: async ({ request, page }) => {
|
|
786
|
+
// 4. Interações human-like
|
|
787
|
+
await page.goto(request.url, { waitUntil: 'domcontentloaded' });
|
|
788
|
+
|
|
789
|
+
// Esperar elemento aparecer
|
|
790
|
+
await page.waitForSelector('h1', { timeout: 10000 });
|
|
791
|
+
|
|
792
|
+
// Interagir como humano
|
|
793
|
+
await page.mouse.move(100, 200);
|
|
794
|
+
await page.waitForTimeout(500);
|
|
795
|
+
await page.mouse.click(100, 200);
|
|
796
|
+
|
|
797
|
+
// Extrair dados
|
|
798
|
+
const title = await page.title();
|
|
799
|
+
const content = await page.textContent('body');
|
|
800
|
+
|
|
801
|
+
return { url: request.url, title, content };
|
|
802
|
+
},
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
await crawler.run(['https://example.com']);
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### Camadas de Proteção
|
|
809
|
+
|
|
810
|
+
| Camada | Solução | Função |
|
|
811
|
+
|--------|---------|--------|
|
|
812
|
+
| Browser | patchright | Remove sinais de automação |
|
|
813
|
+
| Stealth | puppeteer-extra-plugin-stealth | Patches adicionais |
|
|
814
|
+
| Fingerprint | Crawlee fingerprint rotation | Rotação de identidade |
|
|
815
|
+
| Rede | Proxies residenciais | Oculta IP real |
|
|
816
|
+
| Comportamento | Randomização de ações | Evita padrões robóticos |
|
|
817
|
+
| TLS | patchright TLS fix | Fingerprint TLS realista |
|
|
818
|
+
|
|
819
|
+
### Configuração de Session Management
|
|
820
|
+
|
|
821
|
+
```javascript
|
|
822
|
+
import { SessionPool } from 'crawlee';
|
|
823
|
+
|
|
824
|
+
const sessionPool = await SessionPool.open({
|
|
825
|
+
maxPoolSize: 100,
|
|
826
|
+
sessionOptions: {
|
|
827
|
+
maxUsageCount: 50, // Reutilizar sessão até 50 vezes
|
|
828
|
+
maxAgeSecs: 3600, // Sessão expira em 1 hora
|
|
829
|
+
},
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// Usar sessão para manter proxy + fingerprint consistentes
|
|
833
|
+
const crawler = new PlaywrightCrawler({
|
|
834
|
+
sessionPool,
|
|
835
|
+
useSessionPool: true,
|
|
836
|
+
sessionOptions: {
|
|
837
|
+
maxUsageCount: 50,
|
|
838
|
+
},
|
|
839
|
+
// ...
|
|
840
|
+
});
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
---
|
|
844
|
+
|
|
845
|
+
## 10. Tabela de Pacotes npm
|
|
846
|
+
|
|
847
|
+
### Pacotes Principais
|
|
848
|
+
|
|
849
|
+
| Pacote | Versão | Descrição | Stars |
|
|
850
|
+
|--------|--------|-----------|-------|
|
|
851
|
+
| patchright | 1.x | Fork do Playwright com anti-detection | 2.2K+ |
|
|
852
|
+
| playwright | 1.45+ | Browser automation (baseline) | 13K+ |
|
|
853
|
+
| puppeteer | 22.x+ | Browser automation | 88K+ |
|
|
854
|
+
| puppeteer-extra | 3.3.x | Plugin system para Puppeteer | 4.5K+ |
|
|
855
|
+
| puppeteer-extra-plugin-stealth | 2.11.x | Stealth patches | 2.5K+ |
|
|
856
|
+
| crawlee | 3.x | Web scraping framework | 15K+ |
|
|
857
|
+
| cloakbrowser | 1.x | Browser fingerprint management | 13.5K+ |
|
|
858
|
+
|
|
859
|
+
### Pacotes de Suporte
|
|
860
|
+
|
|
861
|
+
| Pacote | Versão | Descrição | Stars |
|
|
862
|
+
|--------|--------|-----------|-------|
|
|
863
|
+
| playwright-extra | 1.x | Plugin system para Playwright | 1.2K+ |
|
|
864
|
+
| rebrowser-patches | 1.x | Anti-detection patches | 800+ |
|
|
865
|
+
| browser-fingerprint | 1.x | Geração de fingerprints | 500+ |
|
|
866
|
+
| tls-fingerprint | 1.x | TLS fingerprint generation | 300+ |
|
|
867
|
+
|
|
868
|
+
### Exemplo de package.json
|
|
869
|
+
|
|
870
|
+
```json
|
|
871
|
+
{
|
|
872
|
+
"name": "stealth-scraper",
|
|
873
|
+
"type": "module",
|
|
874
|
+
"dependencies": {
|
|
875
|
+
"patchright": "^1.45.0",
|
|
876
|
+
"puppeteer-extra": "^3.3.6",
|
|
877
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
878
|
+
"crawlee": "^3.11.0",
|
|
879
|
+
"playwright": "^1.45.0"
|
|
880
|
+
},
|
|
881
|
+
"devDependencies": {
|
|
882
|
+
"@types/node": "^22.0.0",
|
|
883
|
+
"typescript": "^5.5.0"
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
## Referências
|
|
891
|
+
|
|
892
|
+
1. Patchright Documentation - https://github.com/patchright/patchright
|
|
893
|
+
2. Crawlee Fingerprinting - https://crawlee.dev/docs/guides/avoid-blocking
|
|
894
|
+
3. JA3 Fingerprinting - https://github.com/salesforce/ja3
|
|
895
|
+
4. JA4 Fingerprinting - https://github.com/FoxIO-LLC/ja4
|
|
896
|
+
5. bot.sannysoft.com - Testes de detecção
|
|
897
|
+
6. nowsecure.nl - Testes de detecção avançada
|
|
898
|
+
7. Creepjs - Fingerprinting avançado
|