Skip to content

Encontrar elementos

Localizar elementos é a base de toda automação. O Pydoll oferece duas formas de fazer isso: find(), onde você descreve o elemento pelos seus atributos HTML, e query(), onde você passa um seletor CSS ou XPath. Ambos aguardam o elemento aparecer, então você nunca escreve laços sleep manuais.

Edite os atributos abaixo e veja o find() localizar o elemento ao vivo. O Pydoll transforma os atributos que você passa em um seletor para você, e o elemento correspondente se destaca.

Encontrar por atributos

O find() é a ferramenta do dia a dia. Você passa os atributos que usaria para descrever o elemento a uma pessoa, e o Pydoll monta o seletor para você.

import asyncio

from pydoll.browser.chromium import Chrome


async def main():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://quotes.toscrape.com')

        quote = await tab.find(class_name='quote')
        text = await quote.find(class_name='text')
        author = await quote.find(class_name='author')
        print(f'{await author.text}: {await text.text}')

asyncio.run(main())

Você pode localizar um elemento por qualquer um destes atributos. Cada um deles retorna a primeira correspondência:

await tab.find(id='username')        # por id
await tab.find(class_name='quote')   # por nome de classe
await tab.find(tag_name='h1')        # por nome de tag
await tab.find(name='username')      # pelo atributo name
await tab.find(text='Login')         # por texto visível

Combine atributos para mais precisão

Passe vários atributos e o find() corresponde ao elemento que tem todos eles (um AND). Use underscores para nomes de atributos com hífen: data-testid vira data_testid, aria-label vira aria_label.

# um <input type="password" name="password">
password = await tab.find(tag_name='input', type='password', name='password')

# um <button class="btn" type="submit">
submit = await tab.find(tag_name='button', class_name='btn', type='submit')

# um atributo data
card = await tab.find(tag_name='div', data_testid='product-card')

Para lógica OU (o elemento pode ter um atributo ou outro), encadeie duas chamadas com raise_exc=False, como mostrado em Lidar com elementos ausentes.

Encontrar todas as correspondências

Passe find_all=True para obter uma lista de todos os elementos correspondentes em vez do primeiro:

await tab.go_to('https://books.toscrape.com')

books = await tab.find(class_name='product_pod', find_all=True)
print(f'{len(books)} books on this page')

for book in books:
    title = await book.find(tag_name='h3')
    price = await book.find(class_name='price_color')
    print(await title.text, await price.text)

Aguardar elementos que carregam tarde

Páginas modernas renderizam conteúdo após o carregamento inicial. Passe timeout (em segundos) e o find() verifica repetidamente até o elemento aparecer ou o tempo se esgotar. Você não adiciona chamadas sleep; a espera já é embutida.

# aguarda até 10 segundos por um elemento que carrega tarde
content = await tab.find(class_name='dynamic-content', timeout=10)

Escolha os timeouts deliberadamente

Curto demais e você perde elementos lentos; longo demais e você espera por coisas que nunca vão aparecer. De cinco a dez segundos serve para a maior parte do conteúdo dinâmico. Para um elemento que só às vezes está presente, combine um timeout curto com raise_exc=False (abaixo).

Encontrar por seletor CSS ou XPath

Quando você já tem um seletor, ou precisa de uma relação que o find() não consegue expressar, use query(). Ele detecta automaticamente CSS ou XPath.

# CSS
submit = await tab.query("button[type='submit']")
required = await tab.query('input[required]', find_all=True)
nested = await tab.query('div.container > .content .item:nth-child(2)')

# XPath: correspondência de texto e relações que o CSS não alcança
button = await tab.query("//button[contains(text(), 'Submit')]")
label_input = await tab.query("//label[text()='Email:']/following-sibling::input")

O query() recebe os mesmos parâmetros find_all, timeout e raise_exc que o find(). Para saber quando usar CSS ou XPath, veja Seletores: CSS e XPath.

Buscar dentro de um elemento

Todo elemento oferece find() e query() restritos à sua própria subárvore, que é como você trabalha com estruturas repetidas como cards ou linhas. Uma busca com escopo percorre todos os descendentes do elemento, não apenas seus filhos diretos, seguindo o comportamento do querySelector.

await tab.go_to('https://books.toscrape.com')

book = await tab.find(class_name='product_pod')

title = await book.find(tag_name='h3')          # em qualquer lugar dentro deste book
price = await book.find(class_name='price_color')
cover = await book.query('img.thumbnail')

Para navegar pela árvore do DOM de forma deliberada (apenas filhos diretos, irmãos, shadow roots), veja Percorrer o DOM.

Lidar com elementos ausentes

Por padrão, o find() levanta ElementNotFound quando nada corresponde. Passe raise_exc=False para obter None em vez disso, o que deixa elementos opcionais e lógica OU nas suas mãos.

from pydoll.exceptions import ElementNotFound

# elemento obrigatório: deixe levantar a exceção
submit = await tab.find(id='submit')

# elemento opcional: trate o None
banner = await tab.find(class_name='promo-banner', timeout=2, raise_exc=False)
if banner:
    close = await banner.find(class_name='close')
    await close.click()

# lógica OU: tente um atributo, depois outro
checkbox = (
    await tab.find(id='terms', raise_exc=False)
    or await tab.find(name='accept_terms', raise_exc=False)
)

Prefira seletores estáveis

Escolha atributos que dificilmente mudarão em um redesign. A estrutura do seu DOM muda com frequência, então seletores que dependem dela quebram com facilidade.

# semântico e estável: sobrevive a um redesign
await tab.find(id='user-profile')
await tab.find(data_testid='submit-button')
await tab.find(name='username')

# preso à estrutura: quebra no momento em que o layout muda
await tab.query('div > div > div:nth-child(3) > input')

Use o seletor mais simples que funcione, e só adicione complexidade quando a página exigir. Use find() para buscas baseadas em atributos e query() para padrões CSS ou XPath que o find() não consegue expressar.

Exemplo completo: fazer login e ler o resultado

Isto faz login em quotes.toscrape.com (que aceita quaisquer credenciais) e confirma o resultado encontrando o link de Logout.

import asyncio

from pydoll.browser.chromium import Chrome


async def main():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://quotes.toscrape.com/login')

        username = await tab.find(id='username')
        await username.type_text('tester', humanize=True)

        password = await tab.find(id='password')
        await password.type_text('secret', humanize=True)

        submit = await tab.find(tag_name='input', type='submit')
        await submit.click()

        logout = await tab.find(text='Logout', timeout=5, raise_exc=False)
        print('Logged in.' if logout else 'Login failed.')

asyncio.run(main())

Próximos passos