Skip to content

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 lxml

Aná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étodoExemploEncontra
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

FerramentaMelhor paraVelocidadeJavaScriptCurva de aprendizado
requests + BeautifulSoupPáginas HTML estáticasRápidaNãoFácil
SeleniumPáginas renderizadas com JSLentaSimMédia
ScrapyCrawling em grande escalaRápidaCom pluginsÍngreme
PlaywrightApps JS modernasMédiaSimMédia
httpx + selectolaxAnálise de alta performanceMuito rápidaNãoFá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.json

Limpeza 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áticaDescrição
Verificar robots.txtRespeitar as regras de crawling do site
Adicionar atrasosUsar time.sleep() entre requisições (1-3 segundos)
Identificar-seDefinir um User-Agent descritivo
Cachear respostasNão re-scrapear páginas já obtidas
Verificar APIsMuitos sites têm APIs públicas mais rápidas e permitidas
Ler os Termos de ServiçoAlguns sites proíbem explicitamente o scraping
Limitar taxaNã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 results

Aná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.

📚