Scraping com Beautiful Soup e requests usando proxy consiste em configurar a biblioteca requests para rotear o tráfego web por um servidor proxy específico antes de analisar o conteúdo HTML com o Beautiful Soup, permitindo rotação de IP, contorno de restrições geográficas e mitigação de bloqueios de IP.
Ao fazer web scraping, requisições diretas de um único endereço IP podem levar a rate limiting, banimentos de IP temporários ou permanentes, ou conteúdo restrito por região. Os serviços de proxy resolvem esses problemas roteando as requisições por endereços IP diferentes, tornando o scraping mais robusto e escalável.
As bibliotecas centrais para essa tarefa são:
* requests: uma biblioteca HTTP para Python, que simplifica o envio de requisições HTTP.
* Beautiful Soup: uma biblioteca Python para analisar documentos HTML e XML.
Configurando proxies com requests
A biblioteca requests suporta a configuração de proxy pelo parâmetro proxies em seus métodos de requisição.
Configuração de um único proxy
Para usar um único proxy, forneça um dicionário mapeando os protocolos (HTTP, HTTPS) para a URL do proxy.
import requests
proxy_http = "http://your_proxy_ip:port"
proxy_https = "https://your_proxy_ip:port" # Muitas vezes idêntico ao HTTP
proxies = {
"http": proxy_http,
"https": proxy_https,
}
try:
response = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
response.raise_for_status()
print("External IP:", response.json().get('origin'))
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
Autenticação de proxy
Para proxies que exigem autenticação, insira as credenciais diretamente na URL do proxy.
import requests
proxy_user = "your_username"
proxy_pass = "your_password"
proxy_host = "your_proxy_ip"
proxy_port = "port"
authenticated_proxy = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
"http": authenticated_proxy,
"https": authenticated_proxy,
}
try:
response = requests.get("http://httpbin.org/ip", proxies=proxies, timeout=10)
response.raise_for_status()
print("External IP (authenticated):", response.json().get('origin'))
except requests.exceptions.RequestException as e:
print(f"Authenticated request failed: {e}")
Proxies rotativos
Em scraping de larga escala, rotacionar por uma lista de proxies é essencial para distribuir as requisições e minimizar o risco de bloqueio.
import requests
import random
import time
proxy_list = [
"http://user1:[email protected]:8000",
"http://user2:[email protected]:8000",
"http://user3:[email protected]:8000",
]
def get_random_proxy():
return random.choice(proxy_list)
def make_proxied_request(url, headers=None, attempt_limit=3):
for attempt in range(attempt_limit):
proxy_url = get_random_proxy()
proxies = {"http": proxy_url, "https": proxy_url}
try:
print(f"Attempt {attempt + 1}: Using proxy {proxy_url.split('@')[-1]} for {url}")
response = requests.get(url, proxies=proxies, headers=headers, timeout=15)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
print(f"Proxy request failed (attempt {attempt + 1}): {e}")
time.sleep(random.uniform(2, 5)) # Atraso antes de tentar de novo com um novo proxy
return None
# Exemplo de uso com uma URL fictícia
try:
target_url = "http://quotes.toscrape.com/"
response = make_proxied_request(target_url)
if response:
print(f"Successfully fetched {target_url} with status code {response.status_code}")
except Exception as e:
print(f"Failed to fetch {target_url} after multiple retries: {e}")
Analisando HTML com o Beautiful Soup
O Beautiful Soup transforma o conteúdo HTML de uma resposta do requests em um objeto Python navegável.
from bs4 import BeautifulSoup
html_doc = """
<html>
<head><title>Example Page</title></head>
<body>
<p class="intro"><b>Welcome!</b></p>
<div id="content">
<a href="/item1" class="product-link">Product A</a>
<a href="/item2" class="product-link">Product B</a>
</div>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# Acessando elementos
print("Page Title:", soup.title.string)
# Encontrando elementos específicos
intro_paragraph = soup.find('p', class_='intro')
print("Intro text:", intro_paragraph.get_text(strip=True))
# Encontrando todos os elementos por classe
product_links = soup.find_all('a', class_='product-link')
for link in product_links:
print(f"Product: {link.get_text()}, URL: {link['href']}")
Integrando proxies ao scraping com Beautiful Soup
Combinar a configuração de proxy com a análise do Beautiful Soup permite um fluxo de scraping completo.
import requests
from bs4 import BeautifulSoup
import random
import time
# --- Configuração de proxy (como definida antes) ---
proxy_list = [
"http://user1:[email protected]:8000",
"http://user2:[email protected]:8000",
# Adicione mais proxies do seu serviço
]
def get_random_proxy():
return random.choice(proxy_list)
def make_proxied_request(url, headers=None, attempt_limit=3):
for attempt in range(attempt_limit):
proxy_url = get_random_proxy()
proxies = {"http": proxy_url, "https": proxy_url}
try:
print(f"Attempt {attempt + 1} for {url}: Using proxy {proxy_url.split('@')[-1]}")
response = requests.get(url, proxies=proxies, headers=headers, timeout=15)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
print(f"Request failed (attempt {attempt + 1}): {e}")
time.sleep(random.uniform(2, 5))
return None
# --- Lógica de scraping ---
def scrape_quotes(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
response = make_proxied_request(url, headers=headers)
if response:
soup = BeautifulSoup(response.text, 'html.parser')
quotes = soup.find_all('div', class_='quote')
data = []
for quote in quotes:
text = quote.find('span', class_='text').get_text(strip=True)
author = quote.find('small', class_='author').get_text(strip=True)
tags = [tag.get_text(strip=True) for tag in quote.find_all('a', class_='tag')]
data.append({"text": text, "author": author, "tags": tags})
return data
return []
# --- Execução ---
if __name__ == "__main__":
target_url = "http://quotes.toscrape.com/"
print(f"Starting scrape of {target_url}")
scraped_data = scrape_quotes(target_url)
if scraped_data:
print(f"Scraped {len(scraped_data)} quotes:")
for i, quote in enumerate(scraped_data[:3]): # Imprime os 3 primeiros por brevidade
print(f" {i+1}. Author: {quote['author']}, Quote: {quote['text'][:50]}...")
else:
print("No data scraped.")
Boas práticas e considerações
Cabeçalhos User-Agent
Servidores web frequentemente inspecionam o cabeçalho User-Agent para identificar o cliente. O User-Agent padrão do requests pode denunciar um bot. Imitar o User-Agent de um navegador comum reduz a detecção.
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Connection": "keep-alive",
}
response = requests.get(url, proxies=proxies, headers=headers)
Atrasos entre requisições e throttling
Requisições rápidas demais podem disparar rate limits ou banimentos de IP. Implemente atrasos entre as requisições, especialmente ao rotacionar proxies. time.sleep() com um intervalo aleatório é eficaz.
import time
import random
# ... dentro de um laço que processa várias URLs ...
time.sleep(random.uniform(2, 7)) # Espera entre 2 e 7 segundos
response = make_proxied_request(next_url, headers=headers)
Tratamento de erros
Um scraping robusto exige tratamento de erros abrangente para problemas de rede, falhas de proxy e respostas do servidor.
* requests.exceptions.RequestException: captura todos os erros relacionados ao requests (conexão, timeout, erros HTTP).
* Códigos de status HTTP: verifique response.status_code. Códigos como 403 (Forbidden), 404 (Not Found), 429 (Too Many Requests) ou 5xx (Server Error) indicam problemas.
* Timeouts: configure o parâmetro timeout em requests.get() para evitar esperas indefinidas.
CAPTCHAs e medidas antiscraping avançadas
Alguns sites empregam mecanismos de detecção avançados, como CAPTCHAs ou desafios JavaScript. Os proxies ajudam na rotação de IP, mas não resolvem isso diretamente. Nesses casos, considere navegadores headless (por exemplo, Selenium, Playwright) ou serviços especializados em resolver CAPTCHAs.
Comparação de tipos de proxy
| Característica | Proxies de datacenter | Proxies residenciais |
|---|---|---|
| Origem do IP | Servidores comerciais, provedores de nuvem | Dispositivos de usuários reais (desktops, celulares) com IPs de ISP |
| Anonimato | Alto, mas os IPs costumam ser reconhecidos como datacenter | Muito alto, os IPs parecem de usuários legítimos |
| Custo | Geralmente menor | Significativamente maior |
| Velocidade | Normalmente mais rápidos, latência menor | Podem ser mais lentos, latência maior |
| Risco de detecção | Risco maior de detecção/bloqueio | Risco menor, ideais para contornar medidas antibot rigorosas |
| Casos de uso | Scraping geral, dados públicos, sites menos protegidos | Alvos de alto valor, e-commerce, redes sociais, geo-targeting |
Considerações legais e éticas
robots.txt: respeite o arquivorobots.txtdo site, que define as regras para crawlers. Acesse-o emhttp://example.com/robots.txt.- Termos de serviço: revise os termos de serviço do site. O scraping pode ser proibido.
- Uso dos dados: garanta conformidade com as regulamentações de proteção de dados (por exemplo, GDPR, CCPA).
- Impacto no servidor: evite sobrecarregar o servidor alvo com requisições. Implemente atrasos adequados.
