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.
InSkillCoach
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égia | Exemplo | Quando usar |
|---|---|---|
By.ID | By.ID, "email" | Sempre como prioridade, se existir um id estável |
By.NAME | By.NAME, "username" | Formulários clássicos |
By.CSS_SELECTOR | By.CSS_SELECTOR, "div.card > a" | Versátil, rápido e legível |
By.XPATH | By.XPATH, "//button[text()='OK']" | Busca por texto ou subida na árvore do DOM |
By.CLASS_NAME | By.CLASS_NAME, "btn-primary" | Uma única classe, sem espaço |
By.TAG_NAME | By.TAG_NAME, "table" | Coleções de elementos |
By.LINK_TEXT | By.LINK_TEXT, "Contact" | Links cujo texto exato é conhecido |
By.PARTIAL_LINK_TEXT | By.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ção | Verifica que |
|---|---|
presence_of_element_located | O elemento existe no DOM |
visibility_of_element_located | O elemento existe e está visível |
element_to_be_clickable | O elemento está visível e habilitado |
text_to_be_present_in_element | Um determinado texto está sendo exibido |
invisibility_of_element_located | Um elemento (spinner) desapareceu |
title_contains | O 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 cadasleeppor uma espera explícita sobre uma condição observável. - Espere pela condição certa:
element_to_be_clickableantes de um clique,invisibility_of_element_locatedno 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 blocofinallyou 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.
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+
Comentários
Os comentários são alimentados pelo GitHub Discussions
Conecte-se com o GitHub para participar da discussão