AWS Lambda é uma plataforma serverless que permite executar código sem gerenciar servidores. No entanto, ao trabalhar com scraping de sites, APIs de marketplaces ou automação de tarefas, frequentemente surge um problema: as funções Lambda usam endereços IP da AWS, que são facilmente detectados e bloqueados. Neste guia, vamos explorar como integrar proxies no Lambda, configurar a rotação de IP e evitar erros comuns.
O artigo é voltado para desenvolvedores que automatizam tarefas através do AWS Lambda: scraping de dados de sites protegidos, monitoramento de preços de concorrentes, trabalho com APIs de redes sociais ou marketplaces. Você receberá exemplos prontos de código em Python e Node.js que podem ser usados imediatamente após a leitura.
Por que usar proxies no AWS Lambda
O AWS Lambda, por padrão, utiliza endereços IP do pool da Amazon Web Services. Esses endereços estão em listas públicas e são facilmente identificados por sistemas de proteção contra bots. Aqui estão os principais cenários em que proxies se tornam necessários:
Caso real: Um desenvolvedor configurou o Lambda para monitorar preços no Wildberries a cada 15 minutos. Após 2 dias, o marketplace começou a retornar o erro 403 Forbidden — o IP da AWS foi colocado na lista negra. Após conectar proxies residenciais, o scraping funciona de forma estável há 6 meses.
Principais razões para usar proxies no Lambda:
- Scraping de sites protegidos: Muitos sites bloqueiam solicitações de IPs de data centers da AWS. Proxies permitem mascarar o Lambda como usuários comuns.
- Restrições geolocalizadas: Se você precisa obter dados de um site acessível apenas de um determinado país (por exemplo, preços regionais no Ozon), proxies com a geolocalização necessária resolvem o problema.
- Contornar rate limiting: APIs de muitos serviços limitam o número de solicitações de um único IP. A rotação de proxies permite distribuir a carga.
- Teste A/B de anúncios: Verificação da exibição de anúncios de diferentes regiões para análise de concorrentes.
- Monitoramento de marketplaces: Acompanhamento das posições de produtos, preços de concorrentes no Wildberries, Ozon, Avito sem bloqueios.
As funções Lambda são frequentemente executadas em horários programados (através do CloudWatch Events) ou por gatilhos, o que as torna uma ferramenta ideal para automação. No entanto, sem proxies, tais tarefas rapidamente encontram bloqueios por parte dos recursos-alvo.
Qual tipo de proxy escolher para Lambda
A escolha do tipo de proxy depende da tarefa que sua função Lambda está resolvendo. Vamos explorar três tipos principais e suas aplicações na arquitetura serverless:
| Tipo de proxy | Velocidade | Anonimato | Melhores cenários para Lambda |
|---|---|---|---|
| Proxies de data center | Muito alta (50-200 ms) | Média | Scraping de APIs sem proteção rigorosa, verificações em massa de disponibilidade de sites, monitoramento de SEO |
| Proxies residenciais | Média (300-800 ms) | Muito alta | Scraping de sites protegidos (marketplaces, redes sociais), contornar Cloudflare, trabalhar com APIs do Instagram/Facebook |
| Proxies móveis | Média (400-1000 ms) | Máxima | Trabalho com APIs móveis (TikTok, Instagram), teste de anúncios móveis, contornar as proteções mais rigorosas |
Recomendações para escolha:
- Para scraping de Wildberries, Ozon, Avito: Use proxies residenciais com geolocalização russa. Essas plataformas bloqueiam ativamente IPs de data centers.
- Para monitoramento de APIs sem proteção rigorosa: Proxies de data center são suficientes, eles são mais baratos e rápidos.
- Para trabalhar com APIs do Instagram, Facebook, TikTok: Apenas proxies móveis ou residenciais — essas plataformas detectam e banem data centers.
- Para contornar Cloudflare, PerimeterX: Proxies residenciais com rotação, preferencialmente com sessões fixas (manutenção do IP por 5-30 minutos).
Importante: As funções Lambda têm um limite de tempo de execução (máximo de 15 minutos). Ao usar proxies lentos (residenciais/móveis), considere os atrasos — se uma solicitação através do proxy leva 2 segundos, em 15 minutos você poderá fazer no máximo ~450 solicitações.
Configuração de proxy no Lambda com Python (requests, urllib3)
Python é a linguagem mais popular para funções Lambda, especialmente para tarefas de scraping e automação. Vamos considerar a configuração de proxies com a biblioteca requests, que é usada em 90% dos casos.
Configuração básica de proxy HTTP
A maneira mais simples de conectar um proxy é passar o parâmetro proxies no método requests.get():
import requests
import os
def lambda_handler(event, context):
# Obtendo credenciais do proxy das variáveis de ambiente
proxy_host = os.environ['PROXY_HOST'] # Exemplo: proxy.example.com
proxy_port = os.environ['PROXY_PORT'] # Exemplo: 8080
proxy_user = os.environ['PROXY_USER']
proxy_pass = os.environ['PROXY_PASS']
# Formando a URL do proxy com autenticação
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
'http': proxy_url,
'https': proxy_url
}
try:
# Fazendo a solicitação através do proxy
response = requests.get(
'https://api.example.com/data',
proxies=proxies,
timeout=10 # Importante! Defina o timeout
)
return {
'statusCode': 200,
'body': response.text
}
except requests.exceptions.ProxyError as e:
print(f"Erro de proxy: {e}")
return {
'statusCode': 500,
'body': 'Falha na conexão com o proxy'
}
except requests.exceptions.Timeout as e:
print(f"Erro de timeout: {e}")
return {
'statusCode': 504,
'body': 'Timeout da solicitação'
}
Pontos-chave deste código:
- Variáveis de ambiente: Nunca armazene credenciais de proxy diretamente no código! Use Variáveis de Ambiente nas configurações do Lambda.
- Timeout: Sempre defina um timeout (10-30 segundos). Sem isso, o Lambda pode travar até o tempo máximo de execução expirar.
- Tratamento de erros: Proxies podem estar indisponíveis ou lentos — sempre trate as exceções
ProxyErroreTimeout. - HTTP e HTTPS: Especifique ambos os protocolos no dicionário
proxies, mesmo que você use apenas HTTPS.
Configuração de proxy SOCKS5
Proxies SOCKS5 oferecem um nível mais alto de anonimato e funcionam no nível TCP, tornando-os invisíveis para alguns sistemas de proteção. Para trabalhar com SOCKS5 no requests, é necessária a biblioteca requests[socks]:
import requests
import os
def lambda_handler(event, context):
proxy_host = os.environ['PROXY_HOST']
proxy_port = os.environ['PROXY_PORT']
proxy_user = os.environ['PROXY_USER']
proxy_pass = os.environ['PROXY_PASS']
# Proxy SOCKS5 com autenticação
proxy_url = f"socks5://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
'http': proxy_url,
'https': proxy_url
}
try:
response = requests.get(
'https://www.wildberries.ru/catalog/12345/detail.aspx',
proxies=proxies,
timeout=15
)
# Fazendo o parsing dos dados
return {
'statusCode': 200,
'body': response.text
}
except Exception as e:
print(f"Erro: {e}")
return {
'statusCode': 500,
'body': str(e)
}
Importante para deployment no Lambda: Ao usar SOCKS5, adicione ao requirements.txt:
requests[socks]
PySocks
Verificação de IP através do proxy
Antes de executar a lógica principal, é útil verificar se o proxy está funcionando e retornando o IP correto:
def check_proxy_ip(proxies):
"""Verifica o IP que o mundo externo vê através do proxy"""
try:
response = requests.get(
'https://api.ipify.org?format=json',
proxies=proxies,
timeout=10
)
ip_data = response.json()
print(f"IP atual através do proxy: {ip_data['ip']}")
return ip_data['ip']
except Exception as e:
print(f"Verificação de proxy falhou: {e}")
return None
def lambda_handler(event, context):
# ... configuração do proxy ...
# Verificando IP antes do trabalho principal
current_ip = check_proxy_ip(proxies)
if not current_ip:
return {
'statusCode': 500,
'body': 'Verificação do proxy falhou'
}
# Lógica principal de scraping
# ...
Configuração de proxy no Lambda com Node.js (axios, got)
Node.js é a segunda linguagem mais popular para funções Lambda, especialmente quando é necessária alta performance ao trabalhar com APIs. Vamos considerar a configuração de proxies com as bibliotecas axios e got.
Configuração com axios
Axios é a biblioteca HTTP mais popular para Node.js. Para trabalhar com proxies, será necessário um pacote adicional https-proxy-agent:
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
exports.handler = async (event) => {
// Obtendo credenciais das variáveis de ambiente
const proxyHost = process.env.PROXY_HOST;
const proxyPort = process.env.PROXY_PORT;
const proxyUser = process.env.PROXY_USER;
const proxyPass = process.env.PROXY_PASS;
// Formando a URL do proxy
const proxyUrl = `http://${proxyUser}:${proxyPass}@${proxyHost}:${proxyPort}`;
// Criando o agente para o proxy
const agent = new HttpsProxyAgent(proxyUrl);
try {
const response = await axios.get('https://api.example.com/data', {
httpsAgent: agent,
timeout: 10000 // 10 segundos
});
return {
statusCode: 200,
body: JSON.stringify(response.data)
};
} catch (error) {
console.error('Solicitação falhou:', error.message);
return {
statusCode: 500,
body: JSON.stringify({
error: error.message
})
};
}
};
Instalação de dependências: Adicione ao package.json:
{
"dependencies": {
"axios": "^1.6.0",
"https-proxy-agent": "^7.0.0"
}
}
Configuração SOCKS5 com axios
Para proxies SOCKS5, use o pacote socks-proxy-agent:
const axios = require('axios');
const { SocksProxyAgent } = require('socks-proxy-agent');
exports.handler = async (event) => {
const proxyUrl = `socks5://${process.env.PROXY_USER}:${process.env.PROXY_PASS}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
const agent = new SocksProxyAgent(proxyUrl);
try {
const response = await axios.get('https://www.ozon.ru/api/products', {
httpAgent: agent,
httpsAgent: agent,
timeout: 15000
});
return {
statusCode: 200,
body: JSON.stringify(response.data)
};
} catch (error) {
console.error('Erro:', error.message);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
Alternativa: biblioteca got
Got é uma biblioteca HTTP moderna com suporte nativo a proxies (não requer agentes separados):
const got = require('got');
exports.handler = async (event) => {
const proxyUrl = `http://${process.env.PROXY_USER}:${process.env.PROXY_PASS}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
try {
const response = await got('https://api.example.com/data', {
agent: {
http: new (require('http-proxy-agent'))(proxyUrl),
https: new (require('https-proxy-agent'))(proxyUrl)
},
timeout: {
request: 10000
},
responseType: 'json'
});
return {
statusCode: 200,
body: JSON.stringify(response.body)
};
} catch (error) {
console.error('Erro:', error.message);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
Rotação de proxies no Lambda: como mudar IP automaticamente
A rotação de proxies é crítica para tarefas que precisam fazer muitas solicitações sem bloqueios. Existem duas abordagens principais: usar serviços de proxy com rotação automática ou gerenciar manualmente um pool de proxies.
Rotação automática através do provedor
A maioria dos provedores de proxies residenciais (incluindo ProxyCove) oferece um endpoint com rotação automática — cada solicitação ou a cada N minutos, o IP muda automaticamente:
import requests
import os
def lambda_handler(event, context):
# Proxy com rotação automática
# Formato: rotating.proxy.com:port
# Cada solicitação = novo IP
proxy_url = f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@rotating.proxycove.com:8080"
proxies = {
'http': proxy_url,
'https': proxy_url
}
results = []
# Fazendo 10 solicitações — cada uma com um novo IP
for i in range(10):
try:
response = requests.get(
f'https://api.wildberries.ru/products/{i}',
proxies=proxies,
timeout=10
)
results.append({
'product_id': i,
'status': response.status_code,
'data': response.json()
})
except Exception as e:
results.append({
'product_id': i,
'error': str(e)
})
return {
'statusCode': 200,
'body': json.dumps(results)
}
Rotação manual de um pool de proxies
Se você tiver uma lista de proxies, pode implementar a rotação manualmente. Isso é útil quando você precisa ter controle sobre qual proxy é usado para cada solicitação:
import requests
import random
import json
def lambda_handler(event, context):
# Lista de proxies (pode ser armazenada no DynamoDB ou S3)
proxy_pool = [
{
'host': 'proxy1.example.com',
'port': '8080',
'user': 'user1',
'pass': 'pass1'
},
{
'host': 'proxy2.example.com',
'port': '8080',
'user': 'user2',
'pass': 'pass2'
},
{
'host': 'proxy3.example.com',
'port': '8080',
'user': 'user3',
'pass': 'pass3'
}
]
results = []
for i in range(10):
# Escolhendo um proxy aleatório do pool
proxy = random.choice(proxy_pool)
proxy_url = f"http://{proxy['user']}:{proxy['pass']}@{proxy['host']}:{proxy['port']}"
proxies = {
'http': proxy_url,
'https': proxy_url
}
try:
response = requests.get(
f'https://api.example.com/item/{i}',
proxies=proxies,
timeout=10
)
results.append({
'item': i,
'proxy_used': proxy['host'],
'status': response.status_code
})
except Exception as e:
results.append({
'item': i,
'proxy_used': proxy['host'],
'error': str(e)
})
return {
'statusCode': 200,
'body': json.dumps(results)
}
Sessões fixas para manter o IP
Algumas tarefas exigem que um único IP seja mantido durante a sessão (por exemplo, autenticação em um site). Provedores de proxy oferecem sessões fixas através de um parâmetro na URL:
import requests
import uuid
def lambda_handler(event, context):
# Gerando um session_id único
session_id = str(uuid.uuid4())
# Proxy com sessão fixa (IP mantido por 10 minutos)
proxy_url = f"http://{os.environ['PROXY_USER']}-session-{session_id}:{os.environ['PROXY_PASS']}@sticky.proxycove.com:8080"
proxies = {
'http': proxy_url,
'https': proxy_url
}
# Todas as solicitações neste Lambda serão feitas com um único IP
# 1. Autenticação
login_response = requests.post(
'https://example.com/login',
data={'user': 'test', 'pass': 'test'},
proxies=proxies
)
# 2. Obtenção de dados (usa o mesmo IP)
data_response = requests.get(
'https://example.com/dashboard',
proxies=proxies,
cookies=login_response.cookies
)
return {
'statusCode': 200,
'body': data_response.text
}
Armazenamento de credenciais de proxy através de Variáveis de Ambiente
Nunca armazene credenciais de proxy (login, senha, host) diretamente no código da função Lambda. A AWS oferece várias maneiras seguras de armazenar dados confidenciais:
1. Variáveis de Ambiente (método básico)
No console do AWS Lambda → Configuração → Variáveis de ambiente, adicione:
PROXY_HOST= proxy.example.comPROXY_PORT= 8080PROXY_USER= seu_nome_de_usuarioPROXY_PASS= sua_senha
A AWS criptografa automaticamente as Variáveis de Ambiente em repouso. Acesso a elas no código:
# Python
import os
proxy_host = os.environ['PROXY_HOST']
// Node.js
const proxyHost = process.env.PROXY_HOST;
2. AWS Secrets Manager (recomendado para produção)
Para máxima segurança, use o AWS Secrets Manager — ele fornece rotação automática de segredos e controle de acesso detalhado:
import boto3
import json
from botocore.exceptions import ClientError
def get_proxy_credentials():
secret_name = "proxy-credentials"
region_name = "us-east-1"
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name
)
try:
get_secret_value_response = client.get_secret_value(
SecretId=secret_name
)
secret = json.loads(get_secret_value_response['SecretString'])
return secret
except ClientError as e:
print(f"Erro ao recuperar segredo: {e}")
raise e
def lambda_handler(event, context):
# Obtendo credenciais do Secrets Manager
creds = get_proxy_credentials()
proxy_url = f"http://{creds['user']}:{creds['password']}@{creds['host']}:{creds['port']}"
# Usando o proxy
# ...
Importante: Não se esqueça de adicionar permissões IAM à função Lambda para acessar o Secrets Manager:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789:secret:proxy-credentials-*"
}
]
}
Erros comuns e suas soluções
Ao trabalhar com proxies no Lambda, os desenvolvedores frequentemente enfrentam os mesmos problemas. Vamos explorar os mais comuns e suas soluções:
Erro: ProxyError / Timeout de conexão
Sintoma: requests.exceptions.ProxyError: HTTPConnectionPool(host='proxy.example.com', port=8080): Máximo de tentativas excedido
Causas:
- Credenciais do proxy incorretas (login/senha)
- Servidor proxy indisponível ou sobrecarregado
- Firewall bloqueando conexões de saída do Lambda
- Timeout muito curto
Solução:
# 1. Verifique as credenciais
print(f"Usando proxy: {proxy_host}:{proxy_port}")
print(f"Usuário: {proxy_user}")
# 2. Aumente o timeout
response = requests.get(url, proxies=proxies, timeout=30)
# 3. Adicione lógica de retry
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
session = requests.Session()
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=[500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
response = session.get(url, proxies=proxies, timeout=30)
Erro: Verificação de certificado SSL falhou
Sintoma: SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]
Causa: Alguns proxies (especialmente os baratos) usam certificados SSL autoassinados.
Solução (use com cautela!):
# Desativando a verificação SSL (apenas para testes!)
response = requests.get(
url,
proxies=proxies,
verify=False # NÃO use em produção!
)
# Melhor: especifique o caminho para o certificado CA
response = requests.get(
url,
proxies=proxies,
verify='/path/to/ca-bundle.crt'
)
Importante: Desativar a verificação SSL (verify=False) torna a conexão vulnerável a ataques man-in-the-middle. Use apenas para depuração em ambiente de desenvolvimento!
Erro: Timeout do Lambda (Tarefa expirou após X segundos)
Sintoma: A função Lambda termina com erro de timeout, sem esperar pela resposta do proxy.
Causa: Proxies lentos (especialmente residenciais/móveis) + grande número de solicitações.
Solução:
- Aumente o timeout da função Lambda: Configuração → Configuração geral → Timeout (máximo de 15 minutos)
- Reduza o número de solicitações por execução
- Use solicitações assíncronas (asyncio em Python, Promise.all em Node.js)
- Troque para proxies mais rápidos para tarefas não críticas
# Python: solicitações assíncronas para acelerar
import asyncio
import aiohttp
async def fetch_url(session, url, proxy):
async with session.get(url, proxy=proxy, timeout=10) as response:
return await response.text()
async def lambda_handler_async(event, context):
proxy_url = f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
urls = [f'https://api.example.com/item/{i}' for i in range(50)]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url, proxy_url) for url in urls]
results = await asyncio.gather(*tasks)
return {
'statusCode': 200,
'body': json.dumps({'count': len(results)})
}
def lambda_handler(event, context):
return asyncio.run(lambda_handler_async(event, context))
Erro: 407 Proxy Authentication Required
Sintoma: Erro HTTP 407 ao tentar usar o proxy.
Causa: Formato incorreto ao passar as credenciais ou o proxy requer autenticação por IP em vez de login/senha.
Solução:
# Verifique o formato da URL do proxy
# Correto:
proxy_url = f"http://{user}:{password}@{host}:{port}"
# Incorreto (falta o protocolo):
proxy_url = f"{user}:{password}@{host}:{port}" # ❌
# Se o proxy requer autenticação por IP:
# 1. Descubra o IP externo do seu Lambda (pode mudar!)
# 2. Adicione esse IP à lista de permissões do provedor de proxy
# 3. Use o proxy sem user:pass
# Obtendo o IP externo do Lambda:
response = requests.get('https://api.ipify.org?format=json')
lambda_ip = response.json()['ip']
print(f"IP externo do Lambda: {lambda_ip}")
Otimização de desempenho do Lambda com proxies
O uso de proxies adiciona latência a cada solicitação. Aqui estão maneiras comprovadas de minimizar o impacto no desempenho:
1. Pooling de conexões
Reutilize conexões TCP em vez de criar uma nova para cada solicitação:
# Python: use Session em vez de requests.get()
import requests
# Crie a sessão uma vez (pode ser movida para fora do handler)
session = requests.Session()
session.proxies = {
'http': proxy_url,
'https': proxy_url
}
def lambda_handler(event, context):
# Todas as solicitações reutilizam conexões
for i in range(100):
response = session.get(f'https://api.example.com/item/{i}')
# processar resposta...
2. Solicitações paralelas
Se precisar fazer muitas solicitações independentes, execute-as em paralelo:
// Node.js: solicitações paralelas com Promise.all
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
const agent = new HttpsProxyAgent(proxyUrl);
exports.handler = async (event) => {
const urls = Array.from({length: 50}, (_, i) =>
`https://api.example.com/item/${i}`
);
// Todas as solicitações são executadas em paralelo
const promises = urls.map(url =>
axios.get(url, {
httpsAgent: agent,
timeout: 10000
})
);
try {
const results = await Promise.all(promises);
return {
statusCode: 200,
body: JSON.stringify({
count: results.length,
data: results.map(r => r.data)
})
};
} catch (error) {
console.error('Erro:', error.message);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};
3. Cache de resultados
Se os dados mudam raramente, faça cache dos resultados no DynamoDB ou S3:
import boto3
import json
import time
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('proxy-cache')
def get_cached_or_fetch(url, proxies, cache_ttl=3600):
"""Retorna dados do cache ou faz uma solicitação através do proxy"""
# Verificando o cache
try:
response = table.get_item(Key={'url': url})
if 'Item' in response:
item = response['Item']
if time.time() - item['timestamp'] < cache_ttl:
print(f"Cache hit para {url}")
return item['data']
except Exception as e:
print(f"Erro no cache: {e}")
# Cache vazio ou expirado — faz a solicitação
print(f"Cache miss para {url}, buscando...")
response = requests.get(url, proxies=proxies, timeout=10)
data = response.text
# Salvando no cache
try:
table.put_item(Item={
'url': url,
'data': data,
'timestamp': int(time.time())
})
except Exception as e:
print(f"Erro ao salvar no cache: {e}")
return data
4. Escolha o tipo certo de proxy
Comparação de velocidade de diferentes tipos de proxies em condições reais:
| Tipo de proxy | Latência média | Solicitações/minuto (Lambda 1GB RAM) | Recomendação |
|---|---|---|---|
| Data centers | 50-200 ms | 300-600 | Scraping em massa de APIs |
| Residenciais | 300-800 ms | 100-200 | Sites protegidos |
| Móveis | 500-1500 ms | 50-100 | Trabalho com APIs móveis |
Resumo: A escolha do tipo de proxy deve ser baseada na tarefa específica e nas necessidades de desempenho. Proxies de data center são mais rápidos e baratos, mas podem ser bloqueados em sites protegidos. Proxies residenciais oferecem maior anonimato, mas com latência maior. Proxies móveis são ideais para interações com aplicativos móveis, mas são os mais lentos e caros.