Consultar tarifas em muitas rotas ao mesmo tempo é o tipo de tráfego que sites de viagem tentam conter com reCAPTCHA v2, Cloudflare Turnstile e limitação de requisições — normalmente ativados no instante em que o preço muda. A correção não está em reescrever o coletor de dados: é encaixar a resolução do CAPTCHA como mais uma etapa do pipeline, entre a requisição da página e a extração do preço, para o monitor seguir coletando dados sem intervenção manual.
Este guia mostra como montar o workflow em Python, do agendamento à captura do preço, com um exemplo fora dos EUA: workers na região sa-east-1 da AWS (São Paulo) reduzem a latência ao consultar sites de companhias aéreas.
Perguntas frequentes antes de montar o pipeline
Antes de escrever a primeira linha do monitor, vale responder ao que costuma decidir se o projeto compensa o esforço: quanto custa manter rodando, com que frequência checar cada rota, onde hospedar os workers e o que fazer com os dados de tarifa coletados ao longo do tempo.
Quanto custa manter um monitor de tarifas rodando com a CaptchaAI?
Os planos são por thread, com resoluções ilimitadas — o custo depende de quantas verificações simultâneas você roda, não do número de CAPTCHAs. Um BASIC (US$ 15/mês, 5 threads) cobre um monitor pequeno; para dezenas de rotas em paralelo, considere ADVANCE (US$ 90/mês, 50 threads).
Com que frequência vale a pena verificar as tarifas?
De 4 a 8 horas costuma ser o ponto de equilíbrio: checagens mais frequentes detectam mudanças de preço mais rápido, mas também aumentam CAPTCHAs e consumo de threads.
Faz diferença rodar o monitor perto da América do Sul?
Sim, na latência. Workers numa região próxima — sa-east-1 da AWS, em São Paulo — reduzem o tempo de ida e volta até os sites de companhias aéreas.
O LGPD afeta como eu armazeno os dados de tarifa coletados?
Só se o payload guardar dado pessoal além do preço, como e-mail ou CPF do passageiro. Guardando apenas rota, data e valor, o tema não se aplica.
Preciso de proxy para não ser bloqueado durante o monitoramento?
Na prática, sim: sites de viagem bloqueiam IPs de datacenter com muitas requisições seguidas. Combine egress de rede autorizado, rotação de proxy e intervalos realistas.
Como funciona o pipeline de monitoramento
Cada rota agenda, solicita a página e resolve o CAPTCHA antes de repetir a requisição, quando aparece.
Schedule check → Request fare page → CAPTCHA detected?
↓ Yes
Solve via CaptchaAI → Inject token → Retry request
↓ No
Parse fare data → Store → Alert on price change
O que você precisa
- Chave de API CaptchaAI — obtenha a sua em captchaai.com.
- Python 3.8+ com a biblioteca
requests. - Proxy com egress de rede autorizado para os sites de viagem que você for monitorar.
pip install requests
Função auxiliar para resolver CAPTCHA com a CaptchaAI
As funções abaixo resolvem reCAPTCHA v2 e Turnstile via CaptchaAI e devolvem o token pronto para injetar.
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_recaptcha_v2(sitekey, pageurl):
"""Solve reCAPTCHA v2 and return the token."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY, "method": "userrecaptcha",
"googlekey": sitekey, "pageurl": pageurl, "json": 1
}).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit error: {submit.get('request')}")
task_id = submit["request"]
time.sleep(20)
for _ in range(30):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {result['request']}")
time.sleep(5)
raise TimeoutError("Solve timed out")
def solve_turnstile(sitekey, pageurl):
"""Solve Cloudflare Turnstile and return the token."""
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY, "method": "turnstile",
"sitekey": sitekey, "pageurl": pageurl, "json": 1
}).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit error: {submit.get('request')}")
task_id = submit["request"]
time.sleep(10)
for _ in range(30):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve error: {result['request']}")
time.sleep(5)
raise TimeoutError("Solve timed out")
Classe FareMonitor: verificação de tarifas com CAPTCHA
A classe reaproveita as funções acima: detecta o desafio, resolve, injeta o token certo e refaz a requisição. Ajuste _parse_fare por companhia aérea.
import json
from datetime import datetime
class FareMonitor:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {
"http": f"http://{proxy}",
"https": f"http://{proxy}"
}
self.fare_history = {}
def check_fare(self, route):
"""Check fare for a route, solving CAPTCHAs if needed."""
url = route["url"]
response = self.session.get(url)
# Detect CAPTCHA in response
if self._has_recaptcha(response.text):
sitekey = self._extract_sitekey(response.text)
token = solve_recaptcha_v2(sitekey, url)
response = self.session.post(url, data={
"g-recaptcha-response": token,
**route.get("params", {})
})
elif self._has_turnstile(response.text):
sitekey = self._extract_turnstile_key(response.text)
token = solve_turnstile(sitekey, url)
response = self.session.post(url, data={
"cf-turnstile-response": token,
**route.get("params", {})
})
return self._parse_fare(response.text, route)
def _has_recaptcha(self, html):
return "g-recaptcha" in html or "recaptcha/api" in html
def _has_turnstile(self, html):
return "cf-turnstile" in html or "turnstile" in html
def _extract_sitekey(self, html):
# Extract data-sitekey from reCAPTCHA div
if 'data-sitekey="' in html:
start = html.index('data-sitekey="') + 14
end = html.index('"', start)
return html[start:end]
return None
def _extract_turnstile_key(self, html):
if 'data-sitekey="' in html:
idx = html.index("cf-turnstile")
start = html.index('data-sitekey="', idx) + 14
end = html.index('"', start)
return html[start:end]
return None
def _parse_fare(self, html, route):
"""Parse fare data from the response. Customize per target site."""
# Placeholder — implement per site
return {
"route": route["name"],
"timestamp": datetime.now().isoformat(),
"raw_length": len(html)
}
def monitor_routes(self, routes):
"""Check all routes and report price changes."""
results = []
for route in routes:
try:
fare = self.check_fare(route)
results.append(fare)
print(f"[OK] {route['name']}: checked")
except Exception as e:
print(f"[ERROR] {route['name']}: {e}")
return results
# Usage
routes = [
{
"name": "NYC-LAX",
"url": "https://example-airline.com/search?from=JFK&to=LAX&date=2025-08-15",
"params": {"adults": 1}
},
{
"name": "SFO-ORD",
"url": "https://example-airline.com/search?from=SFO&to=ORD&date=2025-08-20",
"params": {"adults": 1}
}
]
monitor = FareMonitor(proxy="user:pass@proxy.example.com:8080")
results = monitor.monitor_routes(routes)
for r in results:
print(json.dumps(r, indent=2))
Como agendar as verificações automaticamente
Rode o monitor em um agendador — cron no Linux, Agendador de Tarefas no Windows, ou um cron job gerenciado se os workers estiverem na nuvem:
# Check fares every 6 hours
0 */6 * * * cd /path/to/project && python fare_monitor.py >> /var/log/fares.log 2>&1
Problemas comuns e como resolver
| Problema | Causa | Correção |
|---|---|---|
| CAPTCHAs frequentes | Muitas requisições do mesmo IP | Aumente o intervalo entre verificações e use rotação de proxy autorizada |
| Preços desatualizados | Páginas em cache | Adicione cabeçalhos anti-cache ou randomize os parâmetros da requisição |
| IP bloqueado | Rate limiting | Aumente os atrasos entre verificações e alterne os proxies |
| Resolução do CAPTCHA falha | Sitekey extraída errada | Confirme se a sitekey corresponde ao CAPTCHA exibido na página |
Checklist para captura confiável de tarifas
- Grave tarifa base, taxas, moeda e classe tarifária no mesmo payload, para comparações históricas continuarem válidas se o layout mudar.
- Mantenha dois seletores alternativos por campo e salve um snapshot do HTML sempre que o parser falhar.
- Registre rota, data de saída, horário da coleta e tempo de resolução do CAPTCHA — o histórico mostra se o site está enrijecendo a detecção.
- Se o payload guardar e-mail ou CPF de passageiro, considere a LGPD; para só acompanhar preço, restrinja o payload a rota, data e valor.
- Valide reCAPTCHA e Turnstile em staging antes de produção: veja o guia de Turnstile em staging.
Comece a monitorar tarifas com a CaptchaAI
Crie sua conta e obtenha a chave de API em captchaai.com. Plugue a chave no monitor acima e deixe o pipeline resolver os CAPTCHAs sozinho.