Web scraping é a técnica de extrair dados de sites automaticamente. Com Python, você pode coletar preços, notícias, imagens e qualquer informação disponível na web de forma programática.

🎯 O Que É Web Scraping?

Imagine precisar coletar preços de produtos de 100 sites diferentes. Fazer isso manualmente levaria horas. Com web scraping, você automatiza esse processo em minutos!

Web scraping é útil para:

  • Monitorar preços de concorrentes
  • Coletar dados para análise e pesquisa
  • Agregar notícias de múltiplas fontes
  • Extrair informações de redes sociais
  • Criar datasets para machine learning

⚖️ Ética e Legalidade

Importante: Antes de fazer scraping, sempre:

  • ✅ Verifique o arquivo robots.txt do site (exemplo: site.com/robots.txt)
  • ✅ Respeite os Termos de Uso do site
  • ✅ Não sobrecarregue o servidor com muitas requisições
  • ✅ Use delays entre requisições
  • ❌ Não use os dados coletados para fins ilegais
  • ❌ Evite scraping de sites que oferecem APIs oficiais

📦 Instalando as Bibliotecas

# BeautifulSoup e requests (para sites estáticos)
pip install beautifulsoup4 requests lxml

# Selenium (para sites dinâmicos com JavaScript)
pip install selenium

# ChromeDriver (necessário para Selenium)
# Baixe de: https://chromedriver.chromium.org/

🍲 BeautifulSoup: Scraping de Sites Estáticos

Exemplo Básico

import requests
from bs4 import BeautifulSoup

# Fazer requisição HTTP
url = "https://example.com"
response = requests.get(url)

# Parse do HTML
soup = BeautifulSoup(response.content, 'html.parser')

# Encontrar elementos
titulo = soup.find('h1').text
print(f"Título: {titulo}")

# Encontrar múltiplos elementos
paragrafos = soup.find_all('p')
for p in paragrafos:
    print(p.text)

Seletores CSS

from bs4 import BeautifulSoup
import requests

url = "https://quotes.toscrape.com/"
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

# Selecionar por classe
citacoes = soup.select('.quote .text')

# Selecionar por ID
elemento = soup.select_one('#content')

# Seletores avançados
autores = soup.select('.quote .author')

# Extrair dados
for citacao, autor in zip(citacoes, autores):
    print(f"{citacao.text} - {autor.text}")

Navegando na Estrutura HTML

import requests
from bs4 import BeautifulSoup

html = """

Produtos

Notebook

R$ 3500

Mouse

R$ 50
""" soup = BeautifulSoup(html, 'html.parser') # Encontrar todos os produtos produtos = soup.find_all('div', class_='produto') for produto in produtos: nome = produto.find('h2').text preco = produto.find('span', class_='preco').text print(f"{nome}: {preco}")

🌐 Requests Avançado

Headers e User-Agent

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

url = "https://example.com"
response = requests.get(url, headers=headers)

# Verificar status
if response.status_code == 200:
    print("Sucesso!")
else:
    print(f"Erro: {response.status_code}")

Tratamento de Erros

import requests
from bs4 import BeautifulSoup
import time

def scrape_com_retry(url, max_tentativas=3):
    """Tenta fazer scraping com retry"""
    for tentativa in range(max_tentativas):
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()  # Lança exceção se status != 200
            return BeautifulSoup(response.content, 'html.parser')
        except requests.RequestException as e:
            print(f"Tentativa {tentativa + 1} falhou: {e}")
            if tentativa < max_tentativas - 1:
                time.sleep(2)  # Aguardar antes de tentar novamente
            else:
                print("Todas as tentativas falharam")
                return None

# Usar a função
soup = scrape_com_retry("https://example.com")
if soup:
    print("Scraping realizado com sucesso!")

🚗 Selenium: Scraping de Sites Dinâmicos

Selenium é necessário quando o site usa JavaScript para carregar conteúdo. BeautifulSoup não executa JavaScript, então não consegue acessar dados carregados dinamicamente.

Configuração Básica

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
import time

# Inicializar o driver
driver = webdriver.Chrome()

try:
    # Acessar o site
    driver.get("https://example.com")
    
    # Esperar elemento carregar (máximo 10 segundos)
    elemento = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CLASS_NAME, "content"))
    )
    
    # Extrair dados
    titulo = driver.find_element(By.TAG_NAME, "h1").text
    print(f"Título: {titulo}")
    
finally:
    # Sempre fechar o navegador
    driver.quit()

Interagindo com Elementos

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

driver = webdriver.Chrome()

try:
    driver.get("https://www.google.com")
    
    # Encontrar campo de busca
    search_box = driver.find_element(By.NAME, "q")
    
    # Digitar texto
    search_box.send_keys("Python web scraping")
    
    # Pressionar Enter
    search_box.send_keys(Keys.RETURN)
    
    # Aguardar resultados carregarem
    time.sleep(2)
    
    # Extrair títulos dos resultados
    resultados = driver.find_elements(By.CSS_SELECTOR, "h3")
    for i, resultado in enumerate(resultados[:5], 1):
        print(f"{i}. {resultado.text}")
        
finally:
    driver.quit()

Scrolling e Paginação

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

driver = webdriver.Chrome()

try:
    driver.get("https://example.com/produtos")
    
    # Scroll até o final da página (para carregar conteúdo lazy-load)
    last_height = driver.execute_script("return document.body.scrollHeight")
    
    while True:
        # Scroll down
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep(2)
        
        # Calcular nova altura
        new_height = driver.execute_script("return document.body.scrollHeight")
        
        # Se não mudou, chegamos ao fim
        if new_height == last_height:
            break
        last_height = new_height
    
    # Agora extrair todos os produtos
    produtos = driver.find_elements(By.CLASS_NAME, "produto")
    print(f"Total de produtos encontrados: {len(produtos)}")
    
finally:
    driver.quit()

Modo Headless (Sem Interface Gráfica)

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

# Configurar opções
options = Options()
options.add_argument('--headless')  # Executar sem abrir navegador
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')

# Inicializar com opções
driver = webdriver.Chrome(options=options)

try:
    driver.get("https://example.com")
    print(f"Título: {driver.title}")
finally:
    driver.quit()

🎓 Projeto Prático: Scraper de Notícias

import requests
from bs4 import BeautifulSoup
from datetime import datetime
import csv

class NoticiasScraper:
    def __init__(self):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
        self.noticias = []
    
    def extrair_noticias(self, url):
        """Extrai notícias de um site exemplo"""
        try:
            response = requests.get(url, headers=self.headers, timeout=10)
            response.raise_for_status()
            
            soup = BeautifulSoup(response.content, 'html.parser')
            
            # Adapte os seletores para o site que você quer fazer scraping
            artigos = soup.find_all('article', class_='noticia')
            
            for artigo in artigos:
                try:
                    titulo = artigo.find('h2').text.strip()
                    resumo = artigo.find('p', class_='resumo').text.strip()
                    link = artigo.find('a')['href']
                    
                    # Adicionar à lista
                    self.noticias.append({
                        'titulo': titulo,
                        'resumo': resumo,
                        'link': link,
                        'data_coleta': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    })
                    
                    print(f"✅ Coletado: {titulo}")
                    
                except AttributeError as e:
                    print(f"⚠️ Erro ao processar artigo: {e}")
                    continue
            
            return len(self.noticias)
            
        except requests.RequestException as e:
            print(f"❌ Erro ao acessar {url}: {e}")
            return 0
    
    def salvar_csv(self, nome_arquivo='noticias.csv'):
        """Salva as notícias em um arquivo CSV"""
        if not self.noticias:
            print("Nenhuma notícia para salvar")
            return
        
        with open(nome_arquivo, 'w', newline='', encoding='utf-8') as arquivo:
            campos = ['titulo', 'resumo', 'link', 'data_coleta']
            writer = csv.DictWriter(arquivo, fieldnames=campos)
            
            writer.writeheader()
            writer.writerows(self.noticias)
        
        print(f"📁 {len(self.noticias)} notícias salvas em {nome_arquivo}")
    
    def exibir_resumo(self):
        """Exibe resumo das notícias coletadas"""
        if not self.noticias:
            print("Nenhuma notícia coletada")
            return
        
        print(f"\n📰 Total de notícias: {len(self.noticias)}\n")
        for i, noticia in enumerate(self.noticias[:5], 1):
            print(f"{i}. {noticia['titulo']}")
            print(f"   {noticia['resumo'][:100]}...")
            print(f"   Link: {noticia['link']}\n")

# Usar o scraper
if __name__ == "__main__":
    scraper = NoticiasScraper()
    
    # URLs para fazer scraping (substitua por sites reais)
    urls = [
        "https://example-noticias.com/tecnologia",
        "https://example-noticias.com/python"
    ]
    
    total = 0
    for url in urls:
        print(f"\n🔍 Coletando de: {url}")
        total += scraper.extrair_noticias(url)
    
    # Exibir e salvar
    scraper.exibir_resumo()
    scraper.salvar_csv()
    
    print(f"\n✅ Scraping concluído! Total: {total} notícias")

💡 Dicas e Boas Práticas

  • Use delays: Adicione time.sleep() entre requisições
  • Respeite robots.txt: Verifique o que o site permite
  • User-Agent: Sempre configure um User-Agent válido
  • Trate erros: Use try/except para lidar com falhas
  • Cache local: Salve HTMLs localmente durante desenvolvimento
  • Evite requests excessivos: Não sobrecarregue o servidor
  • Não ignore erros HTTP: Use response.raise_for_status()

🔧 Ferramentas Úteis

1. SelectorGadget (Chrome Extension)

Ajuda a identificar seletores CSS facilmente.

2. Inspect Element (DevTools)

Use F12 no navegador para explorar a estrutura HTML.

3. Scrapy (Framework Avançado)

# Para projetos maiores
pip install scrapy

⚠️ Desafios Comuns

1. Conteúdo dinâmico (JavaScript)

Solução: Use Selenium em vez de BeautifulSoup.

2. CAPTCHA

Solução: Difícil de contornar. Considere usar APIs oficiais ou serviços como 2Captcha (pago).

3. Rate Limiting (bloqueio por muitas requisições)

Solução: Adicione delays, use proxies rotativos ou respeite os limites.

4. Mudanças na estrutura do site

Solução: Monitore seu scraper e atualize os seletores quando necessário.

🚀 Próximos Passos

Agora que você sabe fazer web scraping, explore:

Web scraping é uma habilidade poderosa que abre portas para automação e análise de dados em escala. Use com responsabilidade e ética! 🎯