Pular para o conteúdo

Playwright & Puppeteer

O Clearcote é só Chromium, então funciona como navegador drop-in para as ferramentas de automação que você já usa.

O pacote clearcote (npm, PyPI e NuGet) transforma as opções de identidade em argumentos nomeados e devolve objetos comuns do Playwright. No primeiro uso, ele baixa o navegador e verifica o SHA-256 — o build aberto sem chave de licença, o build licenciado mais recente com uma (veja Instalação) — e aplica os padrões descritos mais abaixo.

# pip install clearcote
from clearcote import launch

browser = launch(fingerprint="seed-123", platform="windows", brand="Chrome")
page = browser.new_page()
page.goto("https://example.com")
browser.close()

SDK atual: 0.45.0. Desde a 0.23, o launch() em Python e Node roda sobre um diretório de perfil real e descartável (apagado ao fechar), em vez do modo anônimo, para que a superfície que depende do perfil corresponda à de um Chrome real e widevine: true consiga carregar o módulo de DRM. Ele devolve um handle que se comporta como um navegador: newPage() funciona normalmente, mas newContext() devolve esse mesmo contexto de perfil, e não um contexto isolado. Para ter cookie jars separados, inicie navegadores separados; passe ephemeralProfile: false / ephemeral_profile=False para o antigo Browser em modo anônimo, ou userDataDir / user_data_dir para manter o perfil.

A API assíncrona (clearcote.async_api) aceita as mesmas opções de persona e proxy dentro de um loop asyncio e devolve objetos assíncronos do Playwright; o launch() dela usa o modo anônimo, então use launch_persistent_context() para ter um perfil (e para widevine=True). O SDK .NET cobre LaunchEphemeralProfileAsync (recomendado — o LaunchAsync do .NET usa o modo anônimo e não consegue ajustar uma janela headless), LaunchPersistentContextAsync, ServeAsync, download verificado, licenciamento, Geoip e entrada humana (chamadas explícitas a HumanClickAsync / HumanTypeAsync / HumanSelectOptionAsync, e não uma flag de inicialização). Perfis salvos, profile: "auto", verificações de coerência de renderização, Widevine e os helpers de agente são, por enquanto, exclusivos de Python & Node. Para fluxos completos prontos para copiar e colar, veja Exemplos.

Puppeteer e outros clientes CDP (serve)

O SDK não tem um launcher para o Puppeteer. Em vez disso, o serve() inicia o Clearcote com as configurações de inicialização do SDK (persona, proxy, padrões) e um endpoint CDP no loopback, e qualquer cliente CDP se conecta a ele — Puppeteer, o connectOverCDP do Playwright, browser-use, Crawl4AI, Stagehand. Funciona com o build licenciado, e nada adiciona --enable-automation. O humanize roda do lado do Playwright, então não se aplica a um cliente conectado dessa forma.

import { serve } from "clearcote";
import puppeteer from "puppeteer-core";

const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
const browser = await puppeteer.connect({ browserURL: srv.cdpUrl, defaultViewport: null });
const page = await browser.newPage();
await page.goto("https://example.com");
await browser.disconnect();
await srv.close();

No modo headless, o serve() dá ao navegador um display de tamanho real e ajusta a janela à área útil da tela antes que qualquer cliente se conecte (0.31+); passe windowSize / window_size para uma janela menor. No shell, o clearcote serve faz o mesmo como um serviço permanente — e pode dar a cada conexão o próprio navegador, com identidade, proxy, fuso horário e idioma tirados da URL de conexão. Veja Deploy.

Controlando o binário diretamente (build aberto)

Você também pode apontar o seu próprio launcher para o build aberto com executablePath (Node) ou executable_path (Python) e passar as opções de identidade como args. O build licenciado não inicia dessa forma — ele precisa do token de licença que o SDK obtém, então use launch() ou serve(), descritos acima. Remova --enable-automation, como o SDK faz (o Puppeteer e versões mais antigas do Playwright adicionam essa flag, que coloca o Chromium no modo de automação). Nenhum dos padrões do SDK (idioma, política de WebRTC, geometria da janela) se aplica nesse caminho.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        executable_path=r"C:\clearcote\chrome.exe",
        headless=False,
        ignore_default_args=["--enable-automation"],
        args=[
            "--fingerprint=seed-123",
            "--fingerprint-platform=windows",
            "--timezone=America/New_York",
        ],
    )
    page = browser.new_page()
    page.goto("https://abrahamjuliot.github.io/creepjs/")
    browser.close()

Resolva ou pré-baixe o binário verificado

O SDK resolve o navegador nesta ordem: um executablePath / executable_path explícito, depois CLEARCOTE_BINARY, depois uma version que você pediu (ou CLEARCOTE_BROWSER_VERSION), depois o build licenciado, se encontrar uma chave de licença (a opção licenseKey, CLEARCOTE_LICENSE_KEY ou ~/.clearcote/license.key) e, por fim, o build aberto fixado nesta versão do SDK. Um caminho que você informar é verificado antes da inicialização, em busca de arquivos ausentes ou truncados. Chame download / executable_path quando quiser aquecer o cache sem iniciar o navegador, usar um diretório de cache personalizado ou optar, em tempo de execução, pelo build aberto mais recente no GitHub.

from clearcote import download, launch

chrome = download(cache_dir=r"C:\clearcote-cache", auto_update=True)
browser = launch(executable_path=chrome, fingerprint="seed-123")

O modo fixado confere os valores SHA-256 embutidos no SDK. autoUpdate / auto_update é opcional (opt-in) e confere o manifesto de checksums da versão; quando o gpg está disponível, também confere o manifesto assinado contra o fingerprint fixado da chave de assinatura do Clearcote. Isso vale só para o build aberto: com uma chave de licença, o download() baixa o build licenciado atual (escolha um com version ou releaseChannel — veja como escolher um build). No .NET, o DownloadAsync baixa apenas o build aberto; para pré-baixar o licenciado, use ExecutablePathAsync(new LaunchOptions { LicenseKey = … }).

Coerente por padrão (sem flags extras)

Seja qual for a forma como você inicia o navegador, o motor mantém as superfícies secundárias de acordo com a persona escolhida — numa persona Windows, com o que um desktop real com Chrome no Windows reporta. A plataforma da persona é, por padrão, o sistema operacional do host; então, num host Linux, essas superfícies seguem uma persona Linux, a menos que você passe platform. Os limites de getParameter do WebGL (WebGL1 + WebGL2) reportam os valores da persona, limitados ao que a GPU desta máquina consegue de fato entregar, e UNMASKED_RENDERER / UNMASKED_VENDOR são constantes durante a sessão (a mesma GPU em todos os sites, acompanhando a persona). Numa persona Windows, navigator.getBattery() reporta um desktop ligado na tomada, navigator.connection, uma conexão residencial, e AudioContext, a taxa de amostragem e a latência correspondentes do WASAPI do Windows. getScreenDetails() reporta um único monitor, e @media (pointer: fine) / (hover: hover) correspondem a um desktop com mouse.

Verificado no 153 r26, em modo headed no Windows (setembro de 2026): o BrowserScan não reporta bot e o CreepJS mostra 0% de stealth. Atrás de um proxy, adicione geoip para que o fuso horário e o WebRTC correspondam à saída.

Padrões coerentes (substituíveis)

O SDK aplica alguns padrões corretos do ponto de vista de stealth, para que os indícios óbvios não vazem:

  • Inicializações em modo headed não emulam viewport por padrão (viewport: null / no_viewport=True), para que window.innerWidth acompanhe a janela real do sistema operacional — um viewport emulado de 1280×720 dentro de uma janela real é indício de uma janela impossível. Passe um viewport explícito para substituir esse padrão. Num servidor Linux sem gerenciador de janelas (Xvfb, o seu próprio contêiner), onde --start-maximized não faz nada, a janela em modo headed é ajustada à área útil da tela antes da primeira página, como uma janela maximizada de desktop (SDK 0.42.0).
  • Inicializações em modo headless recebem um display realista e uma janela ajustada a ele antes da primeira página: a tela da persona ou, sem persona, um tamanho real de desktop. A partir do SDK 0.42.0, isso vale em todas as plataformas, mesmo quando uma persona não tem efeito, então a página nunca vê a superfície headless crua de 800×600 do motor. Uma opção viewport ou screen sua desliga isso, e um --screen-info seu define o display por conta própria. Um --window-size, --window-position ou --start-maximized seu mantém o display e pula só o ajuste; no serve(), um --window-position sozinho também mantém o display, e só uma flag de tamanho ou o --screen-info deixa a geometria inteiramente por sua conta.
  • Uma única superfície WebGL no Linux: num host Linux, o WebGL de uma persona Linux renderiza via Mesa sobre EGL tanto em modo headless quanto headed (SDK 0.42.0; o host precisa de libegl1), então a página vê uma só string de renderer, lista de extensões e conjunto de limites nos dois modos, na forma OpenGL ES que a maioria das máquinas Linux reais reporta. Sem EGL, uma inicialização em modo headed usa o GL de desktop do Mesa, e uma persona Windows renderiza via SwiftShader. Um --use-angle ou --use-gl seu em args tem prioridade, e uma inicialização em modo headless continua recebendo --ignore-gpu-blocklist junto, para que o WebGL siga funcionando.
  • Claro ou escuro vem da persona no build licenciado a partir do 154 r32: os contextos que o SDK cria deixam desligada a emulação de esquema de cores do Playwright (SDK 0.41.0+), que, do contrário, forçaria o modo claro. Passe colorScheme / color_scheme para emular um mesmo assim.
  • A persona fica fora da linha de comando no build licenciado a partir do 154 r32: o seed, os overrides da persona e as credenciais do proxy chegam ao navegador pelo ambiente dele, e não pela entrada dele na lista de processos (SDK 0.41.0+; personaEnv: false para manter a linha de comando). Veja Opções de inicialização.
  • O WebRTC usa disable_non_proxied_udp por padrão, então nenhum UDP sai por fora do proxy e o endereço da sua própria máquina continua privado. Só o seu próprio --webrtc-ip-handling-policy em args substitui esse padrão — e, no build aberto, webrtcIp / geoip, que voltam a deixar o UDP do WebRTC sair pela sua própria conexão (o build licenciado bloqueia o UDP do WebRTC de qualquer forma). Com essa política e sem webrtcIp, a página não recebe nenhum candidato ICE — atrás de um proxy, passe geoip (ou webrtcIp) para que o WebRTC reporte o endereço do proxy, ou socks5Udp para levar UDP real por um proxy SOCKS5.
  • Atrás de um proxy, QUIC / HTTP-3 fica desligado, como acontece com um Chrome real atrás de um proxy — então nenhum UDP é tentado por fora dele.
  • A plataforma da persona é, por padrão, o sistema operacional do host, e a marca, Google Chrome. Sem timezone e sem geoip, o fuso horário segue o idioma (en-US → Nova York).
  • As credenciais do proxy vão para o navegador, e não para o Playwright, onde o motor oferece suporte: SOCKS5 sempre (o Playwright simplesmente não consegue se autenticar em SOCKS5), HTTP(S) no 151 r19+, para que o cache de páginas continue ativo (Python & Node). Veja abaixo.
  • O humanize faz uma checagem prévia de actionability antes de cada clique confiável (visível / habilitado / estável + uma checagem de sobreposição com elementFromPoint) e, se preciso, recorre ao clique nativo, para que um clique confiável nunca dispare sob um overlay ou no meio de uma animação.
Dica: derive o seed do id da sua própria conta/tenant, para que cada identidade seja reproduzível — mesmo seed, mesmo fingerprint do navegador, sempre. Veja a lista completa de switches em Flags de fingerprint.