0%
Selenium com Python: Automatizando o Navegador

Selenium com Python: Automatizando o Navegador

Aprenda a automatizar o navegador com Selenium 4 e Python: instalação, localização de elementos, esperas explícitas, modo headless e Page Object.

I

InSkillCoach

· min

Selenium com Python: Automatizando o Navegador

Selenium é a biblioteca de referência para controlar um navegador web a partir de um programa. Seja para automatizar testes de interface, preencher formulários repetitivos ou extrair dados de páginas geradas em JavaScript, o Selenium oferece controle total sobre Chrome, Firefox ou Edge. Este guia cobre o essencial do Selenium 4 com Python: da instalação ao padrão Page Object, passando pelas esperas explícitas, que fazem a diferença entre um script frágil e um script confiável.

Instalação

Desde o Selenium 4.6, o gerenciamento de drivers é automático graças ao Selenium Manager, integrado à biblioteca. Não é mais necessário baixar manualmente o chromedriver ou o geckodriver: o Selenium detecta o seu navegador e obtém o driver correspondente.

# Installation de Selenium 4
pip install selenium

# Vérification de la version installée
pip show selenium

Basta garantir que haja um navegador instalado na máquina (Chrome, Firefox ou Edge).

Primeiro script

Veja um script mínimo que abre uma página, lê o título e fecha o navegador:

from selenium import webdriver

# Selenium Manager télécharge automatiquement le driver adapté
driver = webdriver.Chrome()

# Navigation vers une page
driver.get("https://www.python.org")

# Lecture du titre de la page
print(driver.title)
# Welcome to Python.org

# Lecture de l'URL courante
print(driver.current_url)
# https://www.python.org/

# Fermeture propre du navigateur
driver.quit()

Existem dois métodos de fechamento: driver.close() fecha a aba atual, enquanto driver.quit() fecha todas as janelas e encerra o processo do driver. Prefira sempre quit() no final do script.

Localizar elementos

Toda interação começa pela localização de um elemento no DOM. O Selenium 4 usa a classe By combinada com find_element (primeiro elemento encontrado) ou find_elements (lista de todos os elementos).

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.python.org")

# Par identifiant
barre_recherche = driver.find_element(By.ID, "id-search-field")

# Par sélecteur CSS
bouton = driver.find_element(By.CSS_SELECTOR, "button.search-button")

# Par XPath
lien = driver.find_element(By.XPATH, "//a[contains(text(), 'Downloads')]")

# Tous les liens de la page
liens = driver.find_elements(By.TAG_NAME, "a")
print(f"Nombre de liens : {len(liens)}")

driver.quit()

Tabela das estratégias de localização

EstratégiaExemploQuando usar
By.IDBy.ID, "email"Sempre como prioridade, se existir um id estável
By.NAMEBy.NAME, "username"Formulários clássicos
By.CSS_SELECTORBy.CSS_SELECTOR, "div.card > a"Versátil, rápido e legível
By.XPATHBy.XPATH, "//button[text()='OK']"Busca por texto ou subida na árvore do DOM
By.CLASS_NAMEBy.CLASS_NAME, "btn-primary"Uma única classe, sem espaço
By.TAG_NAMEBy.TAG_NAME, "table"Coleções de elementos
By.LINK_TEXTBy.LINK_TEXT, "Contact"Links cujo texto exato é conhecido
By.PARTIAL_LINK_TEXTBy.PARTIAL_LINK_TEXT, "Cont"Links cujo texto varia ligeiramente

Como regra geral: prefira By.ID e, em seguida, os seletores CSS. Reserve o XPath para os casos que o CSS não cobre (seleção por texto, navegação até um elemento pai).

Interagir com os elementos

Clique e digitação de texto

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.get("https://www.python.org")

champ = driver.find_element(By.ID, "id-search-field")

# Saisie de texte
champ.send_keys("selenium")

# Validation avec la touche Entrée
champ.send_keys(Keys.RETURN)

# Effacer un champ avant une nouvelle saisie
champ = driver.find_element(By.ID, "id-search-field")
champ.clear()
champ.send_keys("nouvelle recherche")

driver.quit()

Listas suspensas

Para elementos <select>, o Selenium fornece a classe utilitária Select:

from selenium.webdriver.support.ui import Select

element_select = driver.find_element(By.ID, "pays")
select = Select(element_select)

# Trois façons de sélectionner une option
select.select_by_visible_text("France")
select.select_by_value("fr")
select.select_by_index(2)

# Lire l'option sélectionnée
print(select.first_selected_option.text)

Ler as propriedades de um elemento

element = driver.find_element(By.CSS_SELECTOR, "h1")

print(element.text)                        # Texte visible
print(element.get_attribute("class"))      # Valeur d'un attribut
print(element.is_displayed())              # True si visible
print(element.is_enabled())                # True si actif

Esperas: implícitas vs explícitas

Este é o ponto mais importante deste guia. As páginas modernas carregam o conteúdo em JavaScript de forma assíncrona: um elemento pode ainda não existir no momento em que o script o procura. Sem espera, você obtém erros NoSuchElementException aleatórios.

Espera implícita

A espera implícita se aplica globalmente: a cada find_element, o Selenium tenta novamente durante o tempo indicado antes de lançar uma exceção.

driver = webdriver.Chrome()

# Attendre jusqu'à 10 secondes pour chaque recherche d'élément
driver.implicitly_wait(10)

É simples, mas insuficiente: a espera implícita verifica apenas a presença no DOM, não a visibilidade nem a possibilidade de clique. Um elemento pode existir, mas estar oculto ou desabilitado.

Espera explícita (recomendada)

A espera explícita mira uma condição precisa sobre um elemento específico, com WebDriverWait e o módulo expected_conditions:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("https://www.python.org")

# Attendre jusqu'à 10 secondes que l'élément soit cliquable
wait = WebDriverWait(driver, 10)
bouton = wait.until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "button.search-button"))
)
bouton.click()

driver.quit()

Condições mais úteis:

CondiçãoVerifica que
presence_of_element_locatedO elemento existe no DOM
visibility_of_element_locatedO elemento existe e está visível
element_to_be_clickableO elemento está visível e habilitado
text_to_be_present_in_elementUm determinado texto está sendo exibido
invisibility_of_element_locatedUm elemento (spinner) desapareceu
title_containsO título da página contém uma string

Regra de ouro: nunca use time.sleep() para esperar um elemento. Um sleep curto demais deixa o script instável; um sleep longo demais o torna lento sem necessidade. A espera explícita termina assim que a condição é satisfeita. Evite também misturar esperas implícitas e explícitas: os tempos de espera podem se acumular de forma imprevisível.

Modo headless

O modo headless executa o navegador sem interface gráfica. É indispensável em um servidor de integração contínua:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless=new")       # Nouveau mode headless de Chrome
options.add_argument("--window-size=1920,1080")  # Taille de fenêtre fixe

driver = webdriver.Chrome(options=options)
driver.get("https://www.python.org")
print(driver.title)
# Welcome to Python.org

driver.quit()

Sempre fixe o tamanho da janela no modo headless: por padrão ela é pequena e alguns elementos podem ficar ocultos por causa de uma exibição responsiva.

Capturas de tela

As capturas são valiosas para diagnosticar falhas em testes:

# Capture de la page visible
driver.save_screenshot("page.png")

# Capture d'un élément précis
element = driver.find_element(By.ID, "content")
element.screenshot("element.png")

Boa prática: capture sistematicamente uma imagem no bloco except dos seus testes para ver o estado da página no momento da falha.

Iframes e várias janelas

Iframes

Um elemento dentro de uma <iframe> fica invisível para o Selenium enquanto você não trocar o contexto:

# Basculer vers l'iframe (par élément, nom ou index)
iframe = driver.find_element(By.CSS_SELECTOR, "iframe#editeur")
driver.switch_to.frame(iframe)

# Interagir avec le contenu de l'iframe
driver.find_element(By.TAG_NAME, "body").send_keys("Bonjour")

# Revenir au document principal
driver.switch_to.default_content()

Janelas e abas

Cada janela possui um identificador (handle). Para seguir um link que abre uma nova aba:

fenetre_principale = driver.current_window_handle

# Le clic ouvre un nouvel onglet
driver.find_element(By.LINK_TEXT, "Documentation").click()

# Basculer vers le nouvel onglet
for handle in driver.window_handles:
    if handle != fenetre_principale:
        driver.switch_to.window(handle)
        break

print(driver.title)  # Titre du nouvel onglet

# Fermer l'onglet et revenir à la fenêtre principale
driver.close()
driver.switch_to.window(fenetre_principale)

O padrão Page Object

Quando os scripts crescem, os seletores se repetem por toda parte e cada mudança na interface quebra dezenas de linhas. O padrão Page Object resolve esse problema: cada página do site é representada por uma classe que encapsula seus seletores e suas ações.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class PageConnexion:
    """Encapsule la page de connexion : sélecteurs et actions."""

    URL = "https://exemple.com/connexion"
    CHAMP_EMAIL = (By.ID, "email")
    CHAMP_MOT_DE_PASSE = (By.ID, "password")
    BOUTON_CONNEXION = (By.CSS_SELECTOR, "button[type='submit']")
    MESSAGE_ERREUR = (By.CSS_SELECTOR, ".alert-danger")

    def __init__(self, driver):
        self.driver = driver
        self.wait = WebDriverWait(driver, 10)

    def ouvrir(self):
        self.driver.get(self.URL)
        return self

    def se_connecter(self, email, mot_de_passe):
        self.wait.until(
            EC.visibility_of_element_located(self.CHAMP_EMAIL)
        ).send_keys(email)
        self.driver.find_element(*self.CHAMP_MOT_DE_PASSE).send_keys(mot_de_passe)
        self.driver.find_element(*self.BOUTON_CONNEXION).click()

    def message_erreur(self):
        return self.wait.until(
            EC.visibility_of_element_located(self.MESSAGE_ERREUR)
        ).text


# Utilisation dans un test : le test ne connaît aucun sélecteur
driver = webdriver.Chrome()
page = PageConnexion(driver).ouvrir()
page.se_connecter("utilisateur@exemple.com", "mauvais_mot_de_passe")
assert "identifiants invalides" in page.message_erreur().lower()
driver.quit()

Se a interface mudar, você só modifica a classe PageConnexion: todos os testes que a utilizam permanecem intactos.

Boas práticas anti-flaky

Um teste “flaky” falha de forma aleatória sem que o código testado tenha mudado. Veja como evitá-lo:

  • Bana o time.sleep(): substitua cada sleep por uma espera explícita sobre uma condição observável.
  • Espere pela condição certa: element_to_be_clickable antes de um clique, invisibility_of_element_located no spinner de carregamento antes de ler um resultado.
  • Escolha seletores estáveis: prefira atributos dedicados a testes (data-testid) a classes CSS geradas automaticamente.
  • Isole os testes: cada teste cria seus próprios dados e não depende da ordem de execução dos outros.
  • Fixe o tamanho da janela: uma exibição responsiva diferente entre a sua máquina e o servidor de CI altera a disposição dos elementos.
  • Capture a tela em caso de falha: uma imagem e o HTML da página (driver.page_source) aceleram enormemente o diagnóstico.
  • Use driver.quit() em um bloco finally ou em um gerenciador de contexto para nunca deixar processos órfãos.

Conclusão

O Selenium 4 com Python oferece tudo o que é necessário para automatizar um navegador de forma robusta: o gerenciamento automático de drivers simplifica a instalação, a classe By e os seletores CSS cobrem a localização, e as esperas explícitas com WebDriverWait garantem a confiabilidade diante de páginas assíncronas. Para projetos que vão além de alguns scripts, o padrão Page Object estrutura o código e o protege das mudanças na interface.

Para ir além, consulte a documentação oficial do Selenium e explore a integração com o pytest para organizar suas suítes de testes.

InSkillCoach

Sobre InSkillCoach

Especialista em treinamento e tecnologias

Coach especializado em tecnologias avançadas e IA, apoiado pela GNeurone Inc.

Certificações:

  • AWS Certified Solutions Architect – Professional
  • Certificações Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.1k
220

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!