Web Scraping com Python: Guia completo usando Requests, BeautifulSoup e Selenium
Updated on
Você precisa de dados que não estão disponíveis através de APIs -- preços de produtos de sites concorrentes, artigos de pesquisa de portais acadêmicos, vagas de emprego de plataformas de recrutamento ou artigos de notícias de múltiplas fontes. Copiar dados manualmente é lento, propenso a erros e impossível em escala. O web scraping automatiza esse processo, mas escolher a ferramenta ou abordagem errada leva a requisições bloqueadas, parsers quebrados e problemas legais.
Este guia cobre a pilha completa de web scraping em Python: requests + BeautifulSoup para páginas estáticas, Selenium para conteúdo renderizado com JavaScript e Scrapy para crawling em grande escala. Você aprenderá técnicas práticas para lidar com desafios do mundo real.
Início rápido: requests + BeautifulSoup
A combinação mais comum para fazer scraping de páginas HTML estáticas:
import requests
from bs4 import BeautifulSoup
# Buscar a página
url = 'https://books.toscrape.com/'
response = requests.get(url)
response.raise_for_status() # Levantar erro para códigos de status ruins
# Analisar HTML
soup = BeautifulSoup(response.text, 'html.parser')
# Extrair títulos dos livros
books = soup.select('article.product_pod h3 a')
for book in books[:5]:
print(book['title'])Instalação
# Instalar pacotes necessários
# pip install requests beautifulsoup4 lxmlAnálise HTML com BeautifulSoup
Encontrar elementos
from bs4 import BeautifulSoup
html = """
<div class="products">
<div class="product" id="p1">
<h2 class="name">Widget A</h2>
<span class="price">$9.99</span>
<p class="desc">A useful widget</p>
</div>
<div class="product" id="p2">
<h2 class="name">Widget B</h2>
<span class="price">$14.99</span>
<p class="desc">A better widget</p>
</div>
</div>
"""
soup = BeautifulSoup(html, 'html.parser')
# Por tag
print(soup.find('h2').text) # "Widget A"
# Por classe
prices = soup.find_all('span', class_='price')
for p in prices:
print(p.text) # "$9.99", "$14.99"
# Por ID
product = soup.find(id='p2')
print(product.find('h2').text) # "Widget B"
# Seletor CSS
names = soup.select('.product .name')
for n in names:
print(n.text)Seletores comuns
| Método | Exemplo | Encontra |
|---|---|---|
find('tag') | soup.find('h2') | Primeiro elemento h2 |
find_all('tag') | soup.find_all('a') | Todos os elementos âncora |
find(class_='x') | soup.find(class_='price') | Primeiro elemento com a classe |
find(id='x') | soup.find(id='main') | Elemento com o ID |
select('css') | soup.select('div.product > h2') | Correspondências do seletor CSS |
select_one('css') | soup.select_one('#header') | Primeira correspondência CSS |
Extração de dados
from bs4 import BeautifulSoup
html = '<a href="/page/2" class="next" data-page="2">Next Page</a>'
soup = BeautifulSoup(html, 'html.parser')
link = soup.find('a')
# Conteúdo de texto
print(link.text) # "Next Page"
print(link.get_text(strip=True)) # "Next Page" (limpo)
# Atributos
print(link['href']) # "/page/2"
print(link.get('class')) # ['next']
print(link['data-page']) # "2"Tratamento de cabeçalhos e sessões
Muitos sites bloqueiam requisições sem cabeçalhos adequados:
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'en-US,en;q=0.9',
}
# Usar sessão para cookies e cabeçalhos persistentes
session = requests.Session()
session.headers.update(headers)
response = session.get('https://books.toscrape.com/')
soup = BeautifulSoup(response.text, 'html.parser')
print(f"Encontrados {len(soup.select('article.product_pod'))} livros")Paginação
Seguir links da próxima página
import requests
from bs4 import BeautifulSoup
base_url = 'https://books.toscrape.com/catalogue/'
all_books = []
url = 'https://books.toscrape.com/catalogue/page-1.html'
while url:
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
# Extrair livros da página atual
for book in soup.select('article.product_pod'):
title = book.select_one('h3 a')['title']
price = book.select_one('.price_color').text
all_books.append({'title': title, 'price': price})
# Encontrar próxima página
next_btn = soup.select_one('li.next a')
if next_btn:
url = base_url + next_btn['href']
else:
url = None
print(f"Scrapeados {len(all_books)} livros até agora...")
print(f"Total: {len(all_books)} livros")Scraping de páginas JavaScript com Selenium
Quando uma página renderiza conteúdo com JavaScript, requests obtém apenas o HTML bruto antes da renderização. Use Selenium para controlar um navegador real:
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
# Configurar Chrome sem interface
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
try:
driver.get('https://quotes.toscrape.com/js/')
# Aguardar carregamento do conteúdo
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, 'quote'))
)
quotes = driver.find_elements(By.CLASS_NAME, 'quote')
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, 'text').text
author = quote.find_element(By.CLASS_NAME, 'author').text
print(f'"{text}" -- {author}')
finally:
driver.quit()Comparação de ferramentas
| Ferramenta | Melhor para | Velocidade | JavaScript | Curva de aprendizado |
|---|---|---|---|---|
requests + BeautifulSoup | Páginas HTML estáticas | Rápida | Não | Fácil |
Selenium | Páginas renderizadas com JS | Lenta | Sim | Média |
Scrapy | Crawling em grande escala | Rápida | Com plugins | Íngreme |
Playwright | Apps JS modernas | Média | Sim | Média |
httpx + selectolax | Análise de alta performance | Muito rápida | Não | Fácil |
Scrapy para scraping em grande escala
Para rastrear milhares de páginas, Scrapy fornece concorrência integrada, lógica de retry e pipelines de dados:
# spider.py
import scrapy
class BookSpider(scrapy.Spider):
name = 'books'
start_urls = ['https://books.toscrape.com/']
def parse(self, response):
for book in response.css('article.product_pod'):
yield {
'title': book.css('h3 a::attr(title)').get(),
'price': book.css('.price_color::text').get(),
}
# Seguir paginação
next_page = response.css('li.next a::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
# Executar com: scrapy runspider spider.py -o books.jsonLimpeza e armazenamento de dados
import requests
from bs4 import BeautifulSoup
import pandas as pd
# Scrapear dados
url = 'https://books.toscrape.com/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
books = []
for item in soup.select('article.product_pod'):
title = item.select_one('h3 a')['title']
price_text = item.select_one('.price_color').text
price = float(price_text.replace('£', ''))
rating_class = item.select_one('p.star-rating')['class'][1]
books.append({
'title': title,
'price': price,
'rating': rating_class,
})
# Converter para DataFrame
df = pd.DataFrame(books)
print(df.head())
# Salvar como CSV
df.to_csv('books.csv', index=False)Práticas éticas de scraping
| Prática | Descrição |
|---|---|
| Verificar robots.txt | Respeitar as regras de crawling do site |
| Adicionar atrasos | Usar time.sleep() entre requisições (1-3 segundos) |
| Identificar-se | Definir um User-Agent descritivo |
| Cachear respostas | Não re-scrapear páginas já obtidas |
| Verificar APIs | Muitos sites têm APIs públicas mais rápidas e permitidas |
| Ler os Termos de Serviço | Alguns sites proíbem explicitamente o scraping |
| Limitar taxa | Não sobrecarregar servidores com requisições concorrentes |
import time
import requests
def polite_scrape(urls, delay=2):
"""Scraping com atrasos entre requisições."""
results = []
for url in urls:
response = requests.get(url)
results.append(response.text)
time.sleep(delay) # Ser educado
return resultsAnálise de dados coletados
Após coletar dados via web scraping, PyGWalker (opens in a new tab) ajuda a explorar e visualizar o dataset interativamente no Jupyter:
import pandas as pd
import pygwalker as pyg
df = pd.read_csv('scraped_data.csv')
walker = pyg.walk(df)Para executar scripts de scraping iterativamente no Jupyter com assistência de IA, RunCell (opens in a new tab) fornece um ambiente alimentado por IA onde você pode depurar seletores e testar lógica de análise interativamente.
Perguntas frequentes
Qual é a melhor biblioteca Python para web scraping?
Para páginas estáticas, requests + BeautifulSoup é a escolha mais simples e popular. Para páginas renderizadas com JavaScript, use Selenium ou Playwright. Para crawling em grande escala com milhares de páginas, Scrapy fornece concorrência integrada e gerenciamento de pipelines.
Como faço scraping de um site que usa JavaScript?
Use Selenium ou Playwright para controlar um navegador sem interface que execute JavaScript. Alternativamente, verifique a aba Rede do navegador por endpoints de API que retornem dados JSON -- scrapear a API diretamente é mais rápido e confiável que automação de navegador.
Web scraping é legal?
A legalidade do web scraping depende da jurisdição, dos termos de serviço do site e de como os dados são usados. Scrapear dados publicamente disponíveis é geralmente legal em muitas jurisdições, mas sempre verifique o robots.txt e os Termos de Serviço do site. Evite scrapear dados pessoais ou conteúdo protegido por direitos autorais.
Como evito ser bloqueado ao fazer scraping?
Use atrasos entre requisições (1-3 segundos), alterne User-Agents, respeite robots.txt, use sessões para cookies e evite fazer muitas requisições concorrentes. Se for consistentemente bloqueado, verifique se o site tem uma API pública.
Como lidar com paginação no web scraping?
Encontre o link ou botão "próxima página" no HTML, extraia sua URL e siga-o em um loop até que não existam mais páginas. Alternativamente, se as páginas usam parâmetros de consulta (ex: ?page=2), itere pelos números de página diretamente.
Conclusão
O ecossistema de web scraping do Python cobre cada cenário: requests + BeautifulSoup para scraping rápido de páginas estáticas, Selenium para sites pesados em JavaScript e Scrapy para crawling em escala de produção. Comece com a ferramenta mais simples que funcione, adicione complexidade apenas quando necessário, e sempre faça scraping de forma ética -- respeite robots.txt, adicione atrasos e verifique APIs primeiro. Armazene seus dados coletados em formatos estruturados como CSV ou DataFrames para análise imediata.