Conceitos centrais
O Pydoll é construído sobre algumas decisões de design que moldam como você escreve cada script: sem webdriver, uma API em versão síncrona e assíncrona, interações humanizadas e um sistema de eventos. Esta página explica cada uma delas em um nível prático, para que os guias de tarefas a seguir façam sentido.
Sem webdriver
O Pydoll se conecta diretamente ao navegador pelo Chrome DevTools Protocol (CDP), o mesmo protocolo que move o Chrome DevTools quando você abre o inspetor. Não há um executável webdriver no meio, então não há nada para baixar e nenhum "o chromedriver só suporta o Chrome versão X" para depurar.
graph LR
subgraph P["Pydoll"]
direction LR
P1["Seu código"] --> P2["Pydoll"] --> P3["Navegador (CDP)"]
end
subgraph S["Selenium"]
direction LR
S1["Seu código"] --> S2["Cliente WebDriver"] --> S3["chromedriver"] --> S4["Navegador"]
end
Quando você inicia um navegador, o Pydoll lança o Chrome que você já tem instalado com uma porta de depuração remota e abre um WebSocket para o endpoint CDP dele:
Você não gerencia a porta, a conexão nem o processo do navegador; start() faz isso, e o bloco with para o navegador quando você termina.
Os objetos browser e tab
Dois objetos cobrem a maior parte do que você faz. O browser (Chrome ou Edge) é o processo que você lança. A tab, retornada por browser.start(), é o que você controla: navegação, busca de elementos, screenshots, tudo na página acontece através dela.
Veja Abas para gerenciar várias abas ao mesmo tempo, e Contextos de navegador para isolar sessões.
Síncrono e assíncrono
O Pydoll oferece uma API em duas formas. Importe de pydoll.sync e cada chamada bloqueia até o navegador responder, então o script se lê de cima para baixo sem nenhum event loop para gerenciar. Importe de pydoll e as mesmas classes são corrotinas: você usa await em cada chamada dentro de uma função async def e inicia o programa com asyncio.run(). A forma síncrona é gerada a partir da assíncrona, então as duas nunca diferem em métodos, argumentos ou padrões, e todo exemplo desta documentação mostra as duas. Há uma terceira porta de entrada para código que já existe: um script Playwright roda no Pydoll trocando um import, veja Traga seu script Playwright.
Onde a forma assíncrona compensa é na concorrência. Navegação e esperas por elementos passam a maior parte do tempo ociosas, então asyncio.gather as executa ao mesmo tempo em vez de uma após a outra. A forma síncrona obtém o mesmo efeito com threads, porque suas chamadas podem ser feitas de várias threads ao mesmo tempo com segurança:
from concurrent.futures import ThreadPoolExecutor
from pydoll.sync import Chrome
def title_of(browser, url):
tab = browser.new_tab(url)
title = tab.title()
tab.close()
return title
def main():
urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
'https://quotes.toscrape.com/page/3/',
]
with Chrome() as browser:
browser.start()
with ThreadPoolExecutor() as pool:
titles = list(pool.map(lambda url: title_of(browser, url), urls))
print(titles)
main()
import asyncio
from pydoll import Chrome
async def title_of(browser, url):
tab = await browser.new_tab(url)
title = await tab.title()
await tab.close()
return title
async def main():
urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
'https://quotes.toscrape.com/page/3/',
]
async with Chrome() as browser:
await browser.start()
titles = await asyncio.gather(*(title_of(browser, url) for url in urls))
print(titles)
asyncio.run(main())
As três páginas carregam concorrentemente, então tudo leva mais ou menos o tempo da página mais lenta sozinha, não a soma das três.
Novo em Python assíncrono?
Se async, await e gather não são familiares, leia Python assíncrono na prática primeiro. Ele cobre apenas o suficiente de asyncio para você ficar confortável com o restante destes guias.
Interações humanizadas
Por padrão, um clique cai no centro de um elemento e a digitação envia as teclas uma atrás da outra, na velocidade em que o navegador as aceita. Passe humanize=True e o Pydoll move o cursor por um caminho curvo antes de clicar e digita com timing variável, incluindo o eventual erro de digitação corrigido:
A humanização é opcional por interação, então você a usa onde um site observa o comportamento e a dispensa onde velocidade pura importa. Veja Interações parecidas com humanas para o modelo de timing, e Teclado e Mouse para as APIs de entrada completas.
Orientado a eventos
Em vez de consultar a página em um loop, você pode assinar eventos do navegador e executar um callback quando eles disparam. É assim que você captura tráfego de rede, reage a navegações ou espera por uma requisição específica:
import time
from functools import partial
from pydoll.sync import Chrome, NetworkEvent
def on_request(tab, event):
url = event['params']['request']['url']
if '/api/' in url:
print(f'API call: {url}')
def main():
with Chrome() as browser:
tab = browser.start()
tab.enable_network_events()
tab.on(NetworkEvent.REQUEST_WILL_BE_SENT, partial(on_request, tab))
tab.go_to('https://quotes.toscrape.com')
time.sleep(2)
main()
import asyncio
from functools import partial
from pydoll import Chrome, NetworkEvent
async def on_request(tab, event):
url = event['params']['request']['url']
if '/api/' in url:
print(f'API call: {url}')
async def main():
async with Chrome() as browser:
tab = await browser.start()
await tab.enable_network_events()
await tab.on(NetworkEvent.REQUEST_WILL_BE_SENT, partial(on_request, tab))
await tab.go_to('https://quotes.toscrape.com')
await asyncio.sleep(2)
asyncio.run(main())
Ative apenas os domínios de evento que você usa, e desative-os quando terminar. Veja Eventos para o modelo completo e Monitoramento de rede para captura de tráfego.
Funciona em todos os navegadores Chromium
A mesma API controla qualquer navegador Chromium. O Chrome é o alvo principal; o Edge tem suporte completo; outras builds Chromium funcionam apontando binary_location para elas.
from pydoll.sync import Chrome, ChromiumOptions, Edge
# Chrome
with Chrome() as browser:
tab = browser.start()
# Edge
with Edge() as browser:
tab = browser.start()
# Qualquer outra build Chromium (Brave, Vivaldi, Opera, ...)
options = ChromiumOptions()
options.binary_location = '/path/to/brave-browser'
with Chrome(options=options) as browser:
tab = browser.start()
from pydoll import Chrome, ChromiumOptions, Edge
# Chrome
async with Chrome() as browser:
tab = await browser.start()
# Edge
async with Edge() as browser:
tab = await browser.start()
# Qualquer outra build Chromium (Brave, Vivaldi, Opera, ...)
options = ChromiumOptions()
options.binary_location = '/path/to/brave-browser'
async with Chrome(options=options) as browser:
tab = await browser.start()
Próximos passos
- Encontrar elementos: localize elementos com
find()equery(). - Extração estruturada: obtenha dados tipados de uma página com um modelo.
- Eventos: reaja a eventos de página e de rede conforme disparam.
- Chrome DevTools Protocol: o protocolo que o Pydoll fala com o navegador, em profundidade.