
invisible_playwright v0.7.0
Stealth de navegador anti-detecção gratuito para Playwright: fingerprint de Firefox headless indetectável. Raspagem com Python, bypass de recaptcha e detecção de bots. Código aberto.
O Playwright é detectado por anti-bots e captchas.
Este roda em um Firefox anti-detecção com um fingerprint indetectável, compatível com seu código Playwright existente.

Como funciona
Os anti-bots fazem duas perguntas, e o reCAPTCHA, o hCaptcha e o Cloudflare Turnstile pontuam as respostas. O invisible_playwright responde sim para ambas.
1. Este é um navegador real? Sim. É o Firefox, corrigido no nível do código-fonte C++.
- O fingerprint do navegador é definido dentro do motor, não injetado na página: navigator, screen, GPU/WebGL, canvas, fontes, áudio, WebRTC, fuso horário, rede. Headless ou headed, os mesmos valores de qualquer forma.
- Sem shim JS, sem override, sem costura para ler.
2. Uma pessoa real está usando? Sim. As ações são humanizadas no driver.
- Cada clique, hover e arrasto segue um caminho natural de mouse com timing humano, sem cursor teletransportando.
- Cada entrada é byte a byte idêntica a um mouse real: fonte de entrada real, pressão, eventos confiáveis.
Instalação
Windows, no PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
uv init --python ">=3.11" my-project
cd my-project
uv add invisible-playwright
uv run invisible-playwright fetch # one-time download, sha256-verified: 240 MB, about 550 MB unpacked
Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uv init --python ">=3.11" my-project
cd my-project
uv add invisible-playwright
uv run invisible-playwright fetch # one-time download, sha256-verified: 262 MB (x86_64) / 253 MB (arm64), about 550 MB unpacked
Plataformas suportadas: Windows x86_64, Linux x86_64 / arm64.
Em seguida, salve um dos exemplos abaixo como main.py em my-project e execute-o com uv run main.py.
Uso
Impressão digital aleatória por sessão
A API do Playwright, síncrona e assíncrona, sem alterações no código. Os mesmos objetos, as mesmas chamadas, os mesmos valores de retorno. Algumas superfícies estão fora do escopo — tracing, HAR, CDP, o contexto de requisição da API — e cada uma delas recusa com uma frase explicando o motivo, em vez de se comportar mal silenciosamente. Se você já usa o Playwright, a troca leva duas linhas:
- from playwright.sync_api import sync_playwright
- with sync_playwright() as p:
- browser = p.firefox.launch()
+ from invisible_playwright import InvisiblePlaywright
+ with InvisiblePlaywright() as browser:
Cada sessão recebe uma impressão digital distinta (GPU, áudio, fontes, tela, ~200 campos) e movimento de mouse em curva de Bezier.
Sincronização
from invisible_playwright import InvisiblePlaywright
with InvisiblePlaywright(proxy={"server": "socks5://...", "username": "u", "password": "p"}) as browser:
page = browser.new_page()
page.goto("https://example.com")
page.click("#submit") # mouse arcs to the button on a Bezier curve
Assíncrono
from invisible_playwright.async_api import InvisiblePlaywright
async with InvisiblePlaywright(proxy={"server": "socks5://...", "username": "u", "password": "p"}) as browser:
page = await browser.new_page()
await page.goto("https://example.com")
await page.click("#submit")
O objeto browser é um playwright.sync_api.Browser / playwright.async_api.Browser - todos os métodos do Playwright funcionam como estão.
Registre a seed para reproduzir uma execução:
sf = InvisiblePlaywright()
with sf as browser:
print("seed =", sf.seed)
# ...
Impressão digital reproduzível
with InvisiblePlaywright(seed=42) as browser:
... # same GPU, same canvas hash, same audio context, every run
Proxies
proxy = {
"server": "socks5://gate.example.com:1080",
"username": "user",
"password": "pass",
}
with InvisiblePlaywright(proxy=proxy) as browser:
...
Esquemas suportados: socks5, socks4, http, https. O DNS é encaminhado através do proxy por padrão, sem vazamento local.
Fuso horário
O fuso horário do navegador segue timezone=:
# default: timezone is auto-derived from the egress IP (proxy egress if a
# proxy is set, otherwise the host's own public IP)
with InvisiblePlaywright(proxy=proxy) as browser:
...
# explicit IANA zone always wins, the only way to force a specific zone
with InvisiblePlaywright(proxy=proxy, timezone="America/New_York") as browser:
...
Fixando campos específicos de fingerprint
Por padrão, tudo vem de seed. Para forçar valores específicos enquanto o restante permanece derivado da seed:
with InvisiblePlaywright(
seed=42,
pin={
"gpu.renderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0, D3D11)",
"gpu.vendor": "Google Inc. (AMD)",
"screen.width": 2560,
"screen.height": 1440,
"hardware.concurrency": 16,
},
) as browser:
...
Um pin de GPU escolhe uma das personas validadas em vez de definir uma string livre,
porque os ~81 valores de getParameter e a lista de extensões viajam com o
nome do renderer e um detector os verifica de forma cruzada. Um nome que o pool
não contém gera um erro, e o erro lista os que ele contém.
A lista completa de chaves fixáveis, como o pinning interage com o amostrador Bayesiano e os padrões comuns estão em docs/pinning.md.
CLI
O comando instalado é invisible-playwright, com um hífen. python -m invisible_playwright funciona de forma idêntica e não precisa de nada no PATH.
invisible-playwright fetch # download the engine if missing, check every cached
# one against the seal, print the path
invisible-playwright version # wrapper, core and engine versions, and where the
# engine is cached