Traga seu script Playwright
Seu script Playwright funciona até um site começar a bloqueá-lo. O Pydoll roda o mesmo script sobre CDP puro, sem processo driver e sem navegador patcheado, então não há nada para um detector encontrar no transporte e nada para você reescrever. Esta página pega um script Playwright existente, coloca ele para rodar no Pydoll em cinco minutos e depois mostra onde o Pydoll vai além do Playwright quando você precisar.
Você vai aprender
- Como trocar um script com um import
- O que mudou por baixo do seu script
- Como usar recursos do Pydoll a partir de um script Playwright
- O que isso muda e o que não muda na detecção
Troque o import
Substitua playwright.sync_api por pydoll.playwright.sync_api, ou playwright.async_api por pydoll.playwright.async_api. Todo o resto fica igual. Você não instala o pacote playwright nem os navegadores que ele baixa; o Pydoll controla o Chrome ou o Edge que já está na sua máquina.
from pydoll.playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('https://quotes.toscrape.com/login')
page.get_by_label('Username').fill('john')
page.locator('#password').fill('SecretPass123')
page.get_by_role('button', name='Login').click()
page.wait_for_url('**/')
print(page.get_by_role('link', name='Logout').is_visible())
browser.close()
import asyncio
from pydoll.playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://quotes.toscrape.com/login')
await page.get_by_label('Username').fill('john')
await page.locator('#password').fill('SecretPass123')
await page.get_by_role('button', name='Login').click()
await page.wait_for_url('**/')
print(await page.get_by_role('link', name='Logout').is_visible())
await browser.close()
asyncio.run(main())
Rode do jeito que sempre rodou. Os locators continuam preguiçosos e estritos, get_by_role resolve os mesmos elementos, as ações esperam o elemento estar anexado, visível, estável e habilitado, e uma espera que falha lança o mesmo TimeoutError com o mesmo call log.
chromium.launch() aceita as opções que você já passa: headless, args, executable_path, proxy, downloads_path. launch_persistent_context(user_data_dir) e connect_over_cdp(url) também funcionam. firefox e webkit lançam erro, porque o Pydoll controla apenas navegadores baseados em Chromium.
Drop-in para a superfície de automação
A camada cobre o que um script usa: Playwright, Browser, BrowserContext, Page, Frame, Locator, ElementHandle, Keyboard, Mouse, rotas, diálogos e downloads. Ela não cobre o test runner: assertions expect(), fixtures, o plugin do pytest, tracing e vídeo não estão implementados. API do Playwright lista cada classe com o que é completo, parcial ou ausente.
O que mudou por baixo do seu script
O Playwright fala com o navegador por um processo driver escrito em Node. Toda chamada atravessa esse processo, que então fala CDP com o Chrome. Forks de stealth como o Patchright patcheiam esse driver depois do fato, removendo as chamadas que entregam a automação.
O Pydoll não tem driver. Seu page.goto vira comandos CDP enviados direto do Python, pela mesma conexão que a API própria do Pydoll usa. Isso remove os sinais do transporte na origem em vez de patcheá-los:
- O domínio
Runtime, cuja ativação é o sinal de automação mais conhecido, nunca é habilitado para o seu script. Seletores e verificações de acionabilidade rodam em um isolated world de cada frame, avaliado uma vez, e o seu código depage.evaluateroda no main world sem passar poreval. - Sem
--enable-automation, semnavigator.webdriver, sem hooks de console, sem init scripts injetados a cada navegação. - Avaliações não carregam gesto de usuário sintético, popups só abrem a partir de uma ação real do usuário, e um override de
user_agentvem com Client Hints coerentes, como em um navegador que alguém está usando.
O resto do navegador é um Chrome de verdade: as impressões digitais de TLS, HTTP/2 e renderização são as que o Chrome tem, porque é o Chrome.
Alcance o Pydoll a partir de um objeto Playwright
Todo objeto Playwright expõe o objeto Pydoll por baixo, então recursos que o Playwright não tem nome para ficam a um atributo de distância. Você não reescreve o script para usá-los.
| Objeto Playwright | Objeto Pydoll por baixo |
|---|---|
browser.chrome |
Chrome |
page.tab |
Tab |
locator.element_handle().web_element |
WebElement |
Três coisas que um script bloqueado costuma precisar em seguida, cada uma em uma linha:
from pydoll.sync import ExtractionModel, Field
from pydoll.playwright.sync_api import sync_playwright
from examples.fingerprints import FINGERPRINTS
class Quote(ExtractionModel):
text: str = Field(selector='.text')
author: str = Field(selector='.author')
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.tab.apply_fingerprint(FINGERPRINTS['macos_m3_new_york'])
with page.tab.expect_cloudflare_turnstile():
page.goto('https://quotes.toscrape.com')
quotes = page.tab.extract_all(Quote, scope='.quote')
submit = page.get_by_role('link', name='Login').element_handle().web_element
submit.click(humanize=True)
from pydoll import ExtractionModel, Field
from pydoll.playwright.async_api import async_playwright
from examples.fingerprints import FINGERPRINTS
class Quote(ExtractionModel):
text: str = Field(selector='.text')
author: str = Field(selector='.author')
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.tab.apply_fingerprint(FINGERPRINTS['macos_m3_new_york'])
async with page.tab.expect_cloudflare_turnstile():
await page.goto('https://quotes.toscrape.com')
quotes = await page.tab.extract_all(Quote, scope='.quote')
submit = (await page.get_by_role('link', name='Login').element_handle()).web_element
await submit.click(humanize=True)
apply_fingerprint define uma identidade coerente em todas as camadas (Injeção de fingerprint), expect_cloudflare_turnstile clica no widget Turnstile se a navegação dentro do bloco encontrar um (Cloudflare Turnstile), extract_all retorna objetos tipados e validados (Extração estruturada), e humanize=True move o mouse por um caminho curvo com tempo humano (Interações humanizadas). CDP cru também está a uma chamada de distância: page.tab.execute_command(...).
O que isso não muda
O que a detecção ainda vê
O Pydoll remove os sinais de automação que uma biblioteca adiciona; ele não transforma um bot em pessoa. Um navegador headless continua reconhecível pela renderização e pela falta de dispositivos de mídia, então rode com janela ou aplique um perfil de fingerprint que cubra os sinais de headless. A reputação do seu IP conta tanto quanto o navegador; um IP de datacenter falha em desafios que um residencial passa. Sinais embutidos no binário do Chrome não são tocados. E o comportamento importa: cliques instantâneos e digitação perfeitamente regular parecem o que são, e é para isso que existe o humanize=True.
Passando despercebido percorre cada camada com o mínimo de configuração para ela.
Próximos passos
- API do Playwright: a matriz completa de compatibilidade e os comportamentos que diferem.
- Passando despercebido: identidade, comportamento e desafios, nessa ordem.
- Migrando do Selenium e do Playwright: os mesmos movimentos na API própria do Pydoll, quando quiser ir para o nativo.