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.txtdo 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:
- Manipulação de Arquivos - Para salvar os dados coletados
- Dicionários em Python - Estrutura perfeita para armazenar dados
- Curso Completo - Aprenda Python do zero ao avançado
Web scraping é uma habilidade poderosa que abre portas para automação e análise de dados em escala. Use com responsabilidade e ética! 🎯