Skip to content

Interações Semelhantes a Humanas

Um dos principais diferenciais entre uma automação bem-sucedida e bots facilmente detectados é o quão realistas são as interações. O Pydoll fornece ferramentas sofisticadas para tornar sua automação virtualmente indistinguível do comportamento humano.

Status das Funcionalidades

Já Implementado:

  • Teclado Humanizado: Velocidade de digitação variável, erros realistas com correção automática (humanize=True)
  • Scroll Humanizado: Rolagem baseada em física com momentum, fricção, jitter e overshoot (humanize=True)

Em Breve:

  • Módulo de Movimento de Mouse Realista: Trajetórias de mouse com curvas de Bezier, aceleração/desaceleração natural, overshoot e correção
  • Deslocamentos de clique aleatórios automáticos: Parâmetro opcional para randomizar automaticamente as posições de clique dentro dos elementos
  • Comportamento de hover: Atrasos e movimentos realistas ao passar o mouse sobre elementos

Por que Interações Semelhantes a Humanas Importam

Sites modernos empregam técnicas sofisticadas de detecção de bots:

  • Análise de tempo de eventos: Detectando ações impossivelmente rápidas ou perfeitamente cronometradas
  • Rastreamento de movimento do mouse: Identificando movimentos em linha reta ou teletransporte instantâneo
  • Padrões de teclado: Percebendo inserção de texto instantânea sem pressionamentos de tecla individuais
  • Posições de clique: Detectando cliques sempre no centro exato dos elementos
  • Sequências de ação: Identificando padrões não humanos no comportamento do usuário

O Pydoll ajuda você a evitar a detecção, fornecendo métodos de interação realistas que imitam o comportamento real do usuário.

Cliques Realistas

Clique Básico com Eventos de Mouse Simulados

O método click() simula eventos reais de pressionar e soltar o mouse, diferentemente de cliques baseados em JavaScript:

import asyncio
from pydoll.browser.chromium import Chrome

async def realistic_clicking():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com')

        button = await tab.find(id="submit-button")

        # Clique realista básico
        await button.click()

        # O clique inclui:
        # - Movimento do mouse até o elemento
        # - Evento de pressionar o mouse
        # - Tempo de espera (hold) configurável
        # - Evento de soltar o mouse

asyncio.run(realistic_clicking())

Clique com Deslocamento de Posição (Offset)

Usuários reais raramente clicam no centro exato dos elementos. Use deslocamentos para variar as posições dos cliques:

Estado Atual: Cálculo Manual de Deslocamento

Atualmente, você deve calcular manualmente e randomizar os deslocamentos de clique para cada interação. Versões futuras incluirão um parâmetro opcional para randomizar automaticamente as posições de clique dentro dos limites do elemento.

import asyncio
import random
from pydoll.browser.chromium import Chrome

async def click_with_offset():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/form')

        submit_button = await tab.find(tag_name="button", type="submit")

        # Clicar ligeiramente fora do centro (mais natural)
        await submit_button.click(
            x_offset=5,   # 5 pixels à direita do centro
            y_offset=-3   # 3 pixels acima do centro
        )

        # Atualmente: Varie manualmente o deslocamento para cada clique para parecer mais humano
        for item in await tab.find(class_name="clickable-item", find_all=True):
            offset_x = random.randint(-10, 10)
            offset_y = random.randint(-10, 10)
            await item.click(x_offset=offset_x, y_offset=offset_y)
            await asyncio.sleep(random.uniform(0.5, 2.0))

asyncio.run(click_with_offset())

Tempo de Espera (Hold) do Clique Ajustável

Varie a duração do pressionamento do botão do mouse para simular diferentes estilos de clique:

import asyncio
from pydoll.browser.chromium import Chrome

async def variable_hold_time():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com')

        button = await tab.find(class_name="action-button")

        # Clique rápido (padrão é 0.1s)
        await button.click(hold_time=0.05)

        # Clique normal
        await button.click(hold_time=0.1)

        # Clique mais lento e deliberado
        await button.click(hold_time=0.2)

        # Simular hesitação do usuário
        await asyncio.sleep(0.8)
        await button.click(hold_time=0.15)

asyncio.run(variable_hold_time())

Quando Usar click() vs click_using_js()

Entender a diferença é crucial para evitar detecção:

import asyncio
from pydoll.browser.chromium import Chrome

async def click_methods_comparison():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com')

        button = await tab.find(id="interactive-button")

        # Método 1: click() - Simula eventos reais do mouse
        # Dispara todos os eventos do mouse (mousedown, mouseup, click)
        # Respeita o posicionamento do elemento
        # Mais realista e mais difícil de detectar
        # Requer que o elemento esteja visível e dentro da viewport
        await button.click()

        # Método 2: click_using_js() - Usa JavaScript click()
        # Funciona em elementos ocultos
        # Execução mais rápida
        # Contorna sobreposições visuais
        # Pode ser detectado como automação
        # Não dispara a mesma sequência de eventos de um usuário real
        await button.click_using_js()

asyncio.run(click_methods_comparison())

Melhor Prática: Prefira Eventos do Mouse

Use click() para interações voltadas ao usuário para manter o realismo. Reserve click_using_js() para operações de backend, elementos ocultos, ou quando a velocidade é crítica e a detecção não é uma preocupação.

Entrada de Texto Realista

A API de teclado do Pydoll fornece dois modos de digitação para equilibrar velocidade e furtividade.

Entendendo os Modos de Digitação

Modo Parâmetros Comportamento Caso de Uso
Padrão humanize=False Intervalos fixos de 50ms, sem erros Cenários de velocidade, baixo risco
Humanizado humanize=True Timing variável, ~2% de taxa de erros com correção automática Evasão anti-bot

O parâmetro interval está obsoleto. Use humanize=True em vez disso.

Digitação Natural com Humanização

Use humanize=True para simular digitação humana realista com velocidades variáveis e erros ocasionais que são corrigidos automaticamente:

import asyncio
from pydoll.browser.chromium import Chrome

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

        username_field = await tab.find(id="username")
        password_field = await tab.find(id="password")

        # Velocidade variável: 30-120ms entre teclas
        # ~2% de taxa de erros com comportamento de correção realista
        await username_field.type_text("john.doe@example.com", humanize=True)
        await password_field.type_text("MyC0mpl3xP@ssw0rd!", humanize=True)

asyncio.run(natural_typing())

Entrada Rápida para Campos Não Visíveis

Para campos que não exigem realismo (como campos ocultos ou operações de backend), use insert_text():

import asyncio
from pydoll.browser.chromium import Chrome

async def fast_vs_realistic_input():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/form')

        # Digitação realista para campos visíveis
        username = await tab.find(id="username")
        await username.click()
        await username.type_text("john_doe", interval=0.12)

        # Inserção rápida para campos ocultos ou de backend
        hidden_field = await tab.find(id="hidden-token")
        await hidden_field.insert_text("very-long-generated-token-12345678")

        # Digitação realista para campos que importam
        comment = await tab.find(id="comment-box")
        await comment.click()
        await comment.type_text("This looks like human input!", interval=0.15)

asyncio.run(fast_vs_realistic_input())

Controle Avançado de Teclado

Para documentação abrangente sobre controle de teclado, incluindo teclas especiais, combinações de teclas, modificadores e tabelas de referência completas de teclas, veja Controle de Teclado.

Rolagem Realista da Página

O Pydoll fornece uma API dedicada de scroll que aguarda a conclusão da rolagem antes de prosseguir, tornando suas automações mais realistas e confiáveis.

Entendendo os Modos de Scroll

A API de scroll do Pydoll oferece três modos distintos:

Modo Parâmetros Comportamento Caso de Uso
Instantâneo smooth=False Teletransporta para a posição imediatamente Operações focadas em velocidade
Suave smooth=True (padrão) Animação CSS, previsível Simulação de navegação geral
Humanizado humanize=True Motor de física com momentum, jitter, overshoot Evasão anti-bot

Para contornar fingerprinting comportamental, sempre use humanize=True.

Rolagem Básica por Direção

Use o método scroll.by() para rolar a página em qualquer direção com controle preciso:

import asyncio
from pydoll.browser.chromium import Chrome
from pydoll.constants import ScrollPosition

async def basic_scrolling():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/long-page')

        # Teletransporta instantaneamente - mais rápido mas facilmente detectável
        await tab.scroll.by(ScrollPosition.DOWN, 1000, smooth=False)

        # Animação CSS - visual agradável mas timing previsível
        await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
        await tab.scroll.by(ScrollPosition.UP, 300, smooth=True)

        # Motor de física com curvas de Bezier - mais realista
        # Inclui: momentum, fricção, jitter, micro-pausas, overshoot
        await tab.scroll.by(ScrollPosition.DOWN, 500, humanize=True)
        await tab.scroll.by(ScrollPosition.UP, 300, humanize=True)

asyncio.run(basic_scrolling())

Rolagem para Posições Específicas

Navegue para o topo ou o final da página com controle sobre o realismo:

import asyncio
from pydoll.browser.chromium import Chrome

async def scroll_to_positions():
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/article')

        # Ler o início do artigo
        await asyncio.sleep(2.0)

        # Opção 1: Scroll suave (animação CSS, previsível)
        await tab.scroll.to_bottom(smooth=True)
        await asyncio.sleep(1.5)
        await tab.scroll.to_top(smooth=True)

        # Opção 2: Scroll humanizado (motor de física, evasão anti-bot)
        await tab.scroll.to_bottom(humanize=True)
        await asyncio.sleep(1.5)
        await tab.scroll.to_top(humanize=True)

asyncio.run(scroll_to_positions())

Escolhendo o Modo Certo

  • smooth=True: Bom para demos, screenshots e automação geral
  • humanize=True: Essencial quando enfrentando fingerprinting comportamental ou detecção de bots
  • smooth=False: Velocidade máxima quando a furtividade não é uma preocupação

Padrões de Rolagem Semelhantes a Humanos

O motor de scroll do Pydoll usa Curvas de Bezier Cúbicas para simular a física da rolagem humana. Isso inclui:

  • Momentum: Explosão inicial de velocidade seguida de desaceleração gradual.
  • Fricção: Desaceleração natural baseada em "resistência física".
  • Micro-pausas: Breves paradas durante scrolls longos, imitando leitura ou movimento dos olhos.
  • Overshoot: Rolagem ocasional além do alvo e correção de volta.

Este comportamento é automaticamente habilitado quando você usa humanize=True.

import asyncio
import random
from pydoll.browser.chromium import Chrome
from pydoll.constants import ScrollPosition

async def human_like_scrolling():
    """Simular padrões de rolagem naturais ao ler um artigo."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/article')

        # Usuário começa a ler do topo
        await asyncio.sleep(random.uniform(2.0, 4.0))

        # Rolar gradualmente enquanto lê
        # O motor de scroll cuida da física (aceleração/desaceleração)
        for _ in range(random.randint(5, 8)):
            # Distâncias de rolagem variadas (simula velocidade de leitura)
            scroll_distance = random.randint(300, 600)
            await tab.scroll.by(
                ScrollPosition.DOWN, 
                scroll_distance, 
                humanize=True  # Habilita física com curvas de Bezier
            )

            # Pausar para "ler" o conteúdo
            await asyncio.sleep(random.uniform(2.0, 5.0))

        # Scroll rápido para verificar o final
        await tab.scroll.to_bottom(humanize=True)
        await asyncio.sleep(random.uniform(1.0, 2.0))

        # Voltar ao topo para reler algo
        await tab.scroll.to_top(humanize=True)

asyncio.run(human_like_scrolling())

Rolando Elementos para a Visão

Use scroll_into_view() para garantir que elementos estejam visíveis antes de capturar screenshots da página:

import asyncio
from pydoll.browser.chromium import Chrome

async def scroll_for_screenshots():
    """Rolar elementos para a visão antes de capturar screenshots da página."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/product')

        # Rolar para seção de preços antes de tirar screenshot da página completa
        pricing_section = await tab.find(id="pricing")
        await pricing_section.scroll_into_view()
        await tab.take_screenshot(path="page_with_pricing.png")

        # Rolar para seção de avaliações antes do screenshot
        reviews = await tab.find(class_name="reviews")
        await reviews.scroll_into_view()
        await tab.take_screenshot(path="page_with_reviews.png")

        # Rolar para rodapé para capturar estado completo da página
        footer = await tab.find(tag_name="footer")
        await footer.scroll_into_view()
        await tab.take_screenshot(path="page_with_footer.png")

        # Nota: click() já rola automaticamente, então não é necessário:
        # await button.scroll_into_view()  # Desnecessário!
        # await button.click()  # Isso já rola o botão para a visão

asyncio.run(scroll_for_screenshots())

Detectando Conteúdo de Scroll Infinito

Implemente padrões de rolagem para carregar conteúdo lazy-loaded:

import asyncio
from pydoll.browser.chromium import Chrome
from pydoll.constants import ScrollPosition

async def infinite_scroll_loading():
    """Carregar conteúdo em páginas com scroll infinito."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/feed')

        items_loaded = 0
        max_scrolls = 10

        for scroll_num in range(max_scrolls):
            # Rolar até o final para acionar carregamento
            await tab.scroll.to_bottom(smooth=True)

            # Aguardar o conteúdo carregar
            await asyncio.sleep(random.uniform(2.0, 3.0))

            # Verificar se novos itens foram carregados
            items = await tab.find(class_name="feed-item", find_all=True)
            new_count = len(items)

            if new_count == items_loaded:
                print("Sem mais conteúdo para carregar")
                break

            items_loaded = new_count
            print(f"Rolagem {scroll_num + 1}: {items_loaded} itens carregados")

            # Pequena rolagem para cima (comportamento humano)
            if random.random() > 0.7:
                await tab.scroll.by(ScrollPosition.UP, 200, smooth=True)
                await asyncio.sleep(random.uniform(0.5, 1.0))

asyncio.run(infinite_scroll_loading())

Aguarda Automático da Conclusão

Diferentemente de execute_script("window.scrollBy(...)") que retorna imediatamente, a API scroll usa o parâmetro awaitPromise do CDP para aguardar o evento scrollend do navegador. Isso garante que suas ações subsequentes só executem após a rolagem terminar completamente.

Combinando Técnicas para Máximo Realismo

Exemplo Completo de Preenchimento de Formulário

Aqui está um exemplo abrangente combinando todas as técnicas de interação semelhantes a humanas. Isso demonstra a abordagem manual atual para alcançar o máximo realismo — versões futuras automatizarão muito dessa aleatorização:

import asyncio
import random
from pydoll.browser.chromium import Chrome
from pydoll.constants import Key

async def human_like_form_filling():
    """Preencher um formulário com máximo realismo para evitar detecção."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/registration')

        # Esperar um pouco (usuário lendo a página)
        await asyncio.sleep(random.uniform(1.5, 3.0))

        # Preencher o primeiro nome com velocidade de digitação variável
        first_name = await tab.find(id="first-name")
        await first_name.click(
            x_offset=random.randint(-5, 5),
            y_offset=random.randint(-5, 5)
        )
        await asyncio.sleep(random.uniform(0.2, 0.5))

        # Digitação manual caractere por caractere com atrasos aleatórios
        # (Isso será automatizado em versões futuras)
        name_text = "John"
        for char in name_text:
            await first_name.type_text(char, interval=0)
            await asyncio.sleep(random.uniform(0.08, 0.22))

        # Tab para o próximo campo
        await asyncio.sleep(random.uniform(0.3, 0.8))
        await first_name.press_keyboard_key(Key.TAB)

        # Preencher o sobrenome
        await asyncio.sleep(random.uniform(0.2, 0.5))
        last_name = await tab.find(id="last-name")
        await last_name.type_text("Doe", interval=random.uniform(0.1, 0.18))

        # Tab para o email
        await asyncio.sleep(random.uniform(0.4, 1.0))
        await last_name.press_keyboard_key(Key.TAB)

        # Preencher email com pausas realistas
        await asyncio.sleep(random.uniform(0.2, 0.5))
        email = await tab.find(id="email")

        email_text = "john.doe@example.com"
        for i, char in enumerate(email_text):
            await email.type_text(char, interval=0)
            # Pausa mais longa nos símbolos @ e . (natural)
            if char in ['@', '.']:
                await asyncio.sleep(random.uniform(0.2, 0.4))
            else:
                await asyncio.sleep(random.uniform(0.08, 0.2))

        # Simular usuário revisando o que digitou
        await asyncio.sleep(random.uniform(1.0, 2.5))

        # Aceitar checkbox de termos com deslocamento
        terms_checkbox = await tab.find(id="accept-terms")
        await terms_checkbox.click(
            x_offset=random.randint(-3, 3),
            y_offset=random.randint(-3, 3),
            hold_time=random.uniform(0.08, 0.15)
        )

        # Pausar antes de enviar (usuário revisando formulário)
        await asyncio.sleep(random.uniform(1.5, 3.0))

        # Clicar em enviar com parâmetros realistas
        submit_button = await tab.find(tag_name="button", type="submit")
        await submit_button.click(
            x_offset=random.randint(-8, 8),
            y_offset=random.randint(-5, 5),
            hold_time=random.uniform(0.1, 0.2)
        )

        print("Formulário enviado com comportamento semelhante ao humano")

asyncio.run(human_like_form_filling())

Melhores Práticas para Evitar Detecção

Aleatorização Manual Atualmente Necessária

As seguintes melhores práticas representam o estado atual do Pydoll, onde você deve implementar a aleatorização manualmente. Embora isso exija mais código, oferece um controle refinado sobre o comportamento. Versões futuras automatizarão esses padrões, mantendo o mesmo nível de realismo.

1. Sempre Adicione Atrasos Aleatórios

import asyncio
import random
from pydoll.browser.chromium import Chrome

# Ruim: Tempo previsível
await element1.click()
await element2.click()
await element3.click()

# Bom: Tempo variável (atualmente necessário)
await element1.click()
await asyncio.sleep(random.uniform(0.5, 1.5))
await element2.click()
await asyncio.sleep(random.uniform(0.8, 2.0))
await element3.click()

2. Varie as Posições dos Cliques

import asyncio
import random
from pydoll.browser.chromium import Chrome

# Ruim: Sempre clica no centro
for button in buttons:
    await button.click()

# Bom: Posições variadas (atualmente manual)
for button in buttons:
    await button.click(
        x_offset=random.randint(-10, 10),
        y_offset=random.randint(-10, 10)
    )

3. Simule Comportamento Natural do Usuário

import asyncio
import random
from pydoll.browser.chromium import Chrome

async def natural_user_simulation(tab):
    # Usuário chega na página
    await tab.go_to('https://example.com')

    # Usuário lê o conteúdo da página (1-3 segundos)
    await asyncio.sleep(random.uniform(1.0, 3.0))

    # Usuário rola para baixo para ver mais
    await tab.scroll.by(ScrollPosition.DOWN, 300, smooth=True)
    await asyncio.sleep(random.uniform(0.5, 1.5))

    # Usuário encontra e clica no botão
    button = await tab.find(class_name="cta-button")
    await button.click(
        x_offset=random.randint(-5, 5),
        y_offset=random.randint(-5, 5)
    )

    # Usuário espera o conteúdo carregar
    await asyncio.sleep(random.uniform(0.8, 1.5))

4. Combine Múltiplas Técnicas

import asyncio
import random
from pydoll.browser.chromium import Chrome

async def advanced_stealth_automation():
    """Combinar múltiplas técnicas para máxima furtividade."""
    async with Chrome() as browser:
        tab = await browser.start()

        # Usar espera de carregamento de página semelhante à humana
        await tab.go_to('https://example.com/sensitive-page')
        await asyncio.sleep(random.uniform(2.0, 4.0))

        # Rolar realisticamente com a API dedicada
        for _ in range(random.randint(2, 4)):
            scroll_amount = random.randint(200, 500)
            await tab.scroll.by(ScrollPosition.DOWN, scroll_amount, smooth=True)
            await asyncio.sleep(random.uniform(0.8, 2.0))

        # Encontrar elemento com timeout (simulando busca do usuário)
        target = await tab.find(
            class_name="target-element",
            timeout=random.randint(3, 7)
        )

        # Clicar com todos os parâmetros realistas
        await target.click(
            x_offset=random.randint(-12, 12),
            y_offset=random.randint(-8, 8),
            hold_time=random.uniform(0.09, 0.18)
        )

        # Tempo de reação humano
        await asyncio.sleep(random.uniform(0.5, 1.2))

asyncio.run(advanced_stealth_automation())

Trocas entre Desempenho e Realismo

Às vezes, você precisa equilibrar velocidade com realismo:

import asyncio
from pydoll.browser.chromium import Chrome

async def balanced_automation():
    """Escolher o nível de realismo apropriado com base no contexto."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/scraping-target')

        # Fase 1: Interação inicial (alto realismo)
        # É quando os sistemas de detecção estão mais ativos
        login_button = await tab.find(text="Login")
        await asyncio.sleep(random.uniform(1.0, 2.0))
        await login_button.click(
            x_offset=random.randint(-5, 5),
            y_offset=random.randint(-5, 5)
        )

        await asyncio.sleep(random.uniform(0.5, 1.0))

        username = await tab.find(id="username")
        await username.type_text("user@example.com", interval=0.12)

        await asyncio.sleep(random.uniform(0.3, 0.7))

        password = await tab.find(id="password")
        await password.type_text("password123", interval=0.10)

        submit = await tab.find(type="submit")
        await asyncio.sleep(random.uniform(0.8, 1.5))
        await submit.click()

        # Fase 2: Extração de dados autenticada (menos realismo, mais velocidade)
        # Menos escrutínio após autenticação bem-sucedida
        await asyncio.sleep(2)

        # Navegação rápida pelas páginas
        items = await tab.find(class_name="data-item", find_all=True)

        for item in items:
            # Clique rápido sem deslocamentos
            await item.click_using_js()
            await asyncio.sleep(0.3)  # Atraso mínimo

            # Extrair dados
            title = await tab.find(class_name="title")
            data = await title.text

            # Navegação rápida
            await tab.execute_script("window.history.back()")
            await asyncio.sleep(0.5)

asyncio.run(balanced_automation())

Monitorando e Ajustando

Teste o realismo da sua automação:

import asyncio
import random
import time
from pydoll.browser.chromium import Chrome

async def test_interaction_timing():
    """Registrar tempos para garantir padrões realistas."""
    async with Chrome() as browser:
        tab = await browser.start()
        await tab.go_to('https://example.com/test-page')

        # Medir e registrar o tempo de interação
        elements = await tab.find(class_name="clickable", find_all=True)

        timings = []
        last_time = time.time()

        for i, element in enumerate(elements):
            await element.click(
                x_offset=random.randint(-8, 8),
                y_offset=random.randint(-8, 8)
            )

            current_time = time.time()
            elapsed = current_time - last_time
            timings.append(elapsed)

            print(f"Clique {i+1}: {elapsed:.3f}s desde a última ação")
            last_time = current_time

            await asyncio.sleep(random.uniform(0.5, 2.0))

        # Analisar distribuição de tempo
        avg_time = sum(timings) / len(timings)
        print(f"\nTempo médio entre ações: {avg_time:.3f}s")
        print(f"Min: {min(timings):.3f}s, Max: {max(timings):.3f}s")

        # Bom: Tempo variável com média realista (1-2 segundos)
        # Ruim: Tempo constante ou irrealisticamente rápido (<0.1s)

asyncio.run(test_interaction_timing())

Aprenda Mais

Para mais informações sobre métodos de interação com elementos:

Domine as interações semelhantes a humanas, e sua automação será mais confiável, mais difícil de detectar e espelhará mais de perto o comportamento real do usuário.