Monitorar leilões online esbarra quase sempre no mesmo obstáculo: assim que as buscas ficam rápidas ou repetitivas demais para parecer humanas, o reCAPTCHA v2 aparece e interrompe a coleta. A resposta não é desacelerar o monitoramento até ele deixar de ser útil — é resolver o desafio automaticamente e manter o fluxo de dados rodando. Este guia mostra onde o CAPTCHA costuma aparecer em plataformas de leilão, como decidir a frequência de verificação de cada listagem e como automatizar a resolução em Python e JavaScript sem perder um lance importante.
Onde o CAPTCHA aparece ao monitorar leilões online
CAPTCHAs em sites de leilão não aparecem de forma aleatória — eles seguem o padrão de uso que mais se parece com automação: buscas em sequência, muitas requisições vindas do mesmo IP, ou navegação rápida demais entre categorias.
| Ação | Tipo de CAPTCHA | Padrão que aciona o desafio |
|---|---|---|
| Buscar ou navegar em listagens | reCAPTCHA v2 | Buscas sequenciais em alta velocidade |
| Abrir detalhes de uma listagem | reCAPTCHA v2 | Volume alto vindo do mesmo IP |
| Consultar histórico de lances | reCAPTCHA v2 | Recarregamentos repetidos da página de detalhes |
| Navegar por categorias | Cloudflare Turnstile | Velocidade de navegação típica de bot |
| Páginas de alerta de preço | reCAPTCHA v2 | Atualizações frequentes |
Com que frequência verificar cada leilão
A frequência de verificação certa depende do que você está acompanhando — um lance de última hora exige checagens quase em tempo real, enquanto uma lista de observação tolera intervalos bem maiores.
| Frequência de verificação | Caso de uso | Taxa esperada de CAPTCHA |
|---|---|---|
| A cada 30 segundos | Lance nos minutos finais do leilão | Alta — mantenha sessão autenticada e proxies prontos |
| A cada 5 minutos | Acompanhamento de leilão em andamento | Moderada |
| A cada 15 minutos | Lista de observação (watchlist) | Baixa |
| A cada hora | Pesquisa de preços de longo prazo | Mínima |
Se o worker roda fora do Brasil, a latência de rede já consome parte da sua janela de 30 segundos antes mesmo do CAPTCHA aparecer. Hospedar o monitor em uma região como AWS sa-east-1 (São Paulo) reduz o tempo de ida e volta até a maioria dos sites de leilão voltados ao público brasileiro e deixa mais margem para a resolução em si — o reCAPTCHA v2 normalmente resolve em menos de 60 segundos, com alta taxa de sucesso nos tipos suportados.
Como reduzir a frequência de CAPTCHA no monitoramento
Antes de otimizar a resolução em si, vale reduzir quantas vezes o CAPTCHA chega a aparecer:
| Técnica | Impacto |
|---|---|
| Reaproveitar cookies de sessão | Mantém o estado autenticado entre requisições |
| Fazer rotação de proxies | Distribui as requisições entre IPs diferentes |
| Randomizar os intervalos entre requisições | Evita padrões de acesso previsíveis |
| Usar contas autenticadas | Reduz a frequência com que o CAPTCHA é acionado |
Ao armazenar históricos de lances e nomes de usuário coletados durante o monitoramento, vale considerar as obrigações da LGPD sobre retenção e finalidade dos dados — mesmo quando a informação já é pública na listagem, guardar esse histórico por tempo indefinido pode extrapolar o propósito original da coleta.
Monitorando leilões em Python: resolução automática de reCAPTCHA v2
A classe abaixo cobre o fluxo completo: busca paginada, checagem de uma listagem específica e acompanhamento contínuo de lances. O solver só é acionado quando _has_captcha() encontra o desafio na resposta — nenhuma tarefa é enviada à toa.
import requests
import time
import re
from datetime import datetime
class AuctionMonitor:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def search_listings(self, auction_url, query, category=None):
"""Search auction listings, solving CAPTCHAs when triggered."""
params = {"q": query}
if category:
params["category"] = category
response = self.session.get(
f"{auction_url}/search", params=params
)
if self._has_captcha(response.text):
site_key = self._extract_site_key(response.text)
token = self._solve_recaptcha(site_key, f"{auction_url}/search")
response = self.session.post(
f"{auction_url}/search",
data={**params, "g-recaptcha-response": token}
)
return self._parse_listings(response.text)
def monitor_listing(self, auction_url, listing_id):
"""Get current bid and listing details."""
url = f"{auction_url}/item/{listing_id}"
response = self.session.get(url)
if self._has_captcha(response.text):
site_key = self._extract_site_key(response.text)
token = self._solve_recaptcha(site_key, url)
response = self.session.post(url, data={
"g-recaptcha-response": token
})
return self._parse_listing_detail(response.text)
def track_bids(self, auction_url, listing_ids, interval=60):
"""Track bid changes across multiple listings."""
history = {lid: [] for lid in listing_ids}
while True:
for listing_id in listing_ids:
try:
detail = self.monitor_listing(auction_url, listing_id)
previous = history[listing_id]
if previous and detail["current_bid"] != previous[-1]["current_bid"]:
print(f"Bid change on {listing_id}: "
f"${previous[-1]['current_bid']} → ${detail['current_bid']}")
history[listing_id].append(detail)
except Exception as e:
print(f"Error checking {listing_id}: {e}")
time.sleep(interval)
def _has_captcha(self, html):
return "g-recaptcha" in html or "recaptcha" in html.lower()
def _extract_site_key(self, html):
match = re.search(r'data-sitekey="([^"]+)"', html)
if match:
return match.group(1)
match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", html)
if match:
return match.group(1)
raise ValueError("Could not find reCAPTCHA site key")
def _solve_recaptcha(self, site_key, page_url):
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return data["request"]
raise TimeoutError("reCAPTCHA solve timed out")
def _parse_listings(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
def text_or_none(node):
return node.text.strip() if node and node.text else None
def attr_or_none(node, attr):
return node.get(attr) if node else None
listings = []
for item in soup.select(".listing-item, .auction-item"):
listings.append({
"title": text_or_none(item.select_one(".title")),
"current_bid": text_or_none(item.select_one(".price, .bid")),
"time_left": text_or_none(item.select_one(".time-left")),
"url": attr_or_none(item.select_one("a"), "href")
})
return listings
def _parse_listing_detail(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
def text_or_none(node):
return node.text.strip() if node and node.text else None
return {
"title": text_or_none(soup.select_one("h1, .item-title")),
"current_bid": text_or_none(soup.select_one(".current-bid, .price")),
"bid_count": text_or_none(soup.select_one(".bid-count")),
"time_left": text_or_none(soup.select_one(".time-remaining")),
"checked_at": datetime.now().isoformat()
}
# Usage
monitor = AuctionMonitor("YOUR_API_KEY")
listings = monitor.search_listings(
"https://auctions.example.com",
"vintage electronics",
category="collectibles"
)
Alertas de preço em JavaScript: acompanhando lances automaticamente
Para quem prefere Node.js ou roda o monitor direto no navegador, esta versão em JavaScript acompanha uma lista de leilões e dispara um alerta quando o lance atual se aproxima do teto que você definiu.
class AuctionTracker {
constructor(apiKey) {
this.apiKey = apiKey;
this.watchList = new Map();
}
addWatch(listingId, url, maxPrice) {
this.watchList.set(listingId, { url, maxPrice, history: [] });
}
async checkAll() {
const alerts = [];
for (const [id, watch] of this.watchList) {
try {
const detail = await this.fetchListing(watch.url);
watch.history.push(detail);
const price = parseFloat(detail.currentBid.replace(/[^0-9.]/g, ''));
if (price >= watch.maxPrice * 0.9) {
alerts.push({
listing: id,
price,
threshold: watch.maxPrice,
message: `Price approaching limit: $${price} / $${watch.maxPrice}`
});
}
} catch (error) {
alerts.push({ listing: id, error: error.message });
}
}
return alerts;
}
async fetchListing(url) {
const response = await fetch(url);
const html = await response.text();
if (html.includes('g-recaptcha')) {
return this.solveAndFetch(url, html);
}
return this.parseDetail(html);
}
async solveAndFetch(url, html) {
const siteKeyMatch = html.match(/data-sitekey="([^"]+)"/);
if (!siteKeyMatch) throw new Error('No reCAPTCHA site key found');
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'userrecaptcha',
googlekey: siteKeyMatch[1],
pageurl: url,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) {
// Resubmit with token
const response = await fetch(url, {
method: 'POST',
body: new URLSearchParams({ 'g-recaptcha-response': data.request })
});
return this.parseDetail(await response.text());
}
}
throw new Error('reCAPTCHA solve timed out');
}
parseDetail(html) {
// Parse auction listing details from HTML
return {
currentBid: html.match(/current.?bid[^>]*>([^<]+)/i)?.[1]?.trim(),
bidCount: html.match(/(\d+)\s*bids?/i)?.[1],
timeLeft: html.match(/time.?(?:left|remaining)[^>]*>([^<]+)/i)?.[1]?.trim(),
checkedAt: new Date().toISOString()
};
}
}
// Usage
const tracker = new AuctionTracker('YOUR_API_KEY');
tracker.addWatch('item-123', 'https://auctions.example.com/item/123', 500);
tracker.addWatch('item-456', 'https://auctions.example.com/item/456', 200);
const alerts = await tracker.checkAll();
Solução de problemas
| Problema | Causa | Correção |
|---|---|---|
| CAPTCHA em toda requisição | Sem persistência de sessão | Reaproveite requests.Session() entre as chamadas |
| Token reCAPTCHA rejeitado | O token expirou (validade de 2 minutos) | Resolva o CAPTCHA imediatamente antes do envio |
| A página de listagens retorna 0 resultados | O CAPTCHA filtrou o resultado silenciosamente | Verifique se há elementos de CAPTCHA ocultos na resposta |
| IP bloqueado após vários CAPTCHAs | Limite de requisições excedido | Faça rotação de proxies e aumente os intervalos |
Perguntas frequentes
Quantos threads preciso para monitorar vários leilões em paralelo?
Cada thread do seu plano CaptchaAI processa um CAPTCHA por vez; quando o solve termina, a thread fica livre para a próxima tarefa. O plano BASIC (US$ 15/mês, 5 threads) já cobre o monitoramento de algumas listagens com verificações espaçadas. Para acompanhar dezenas de leilões em paralelo com checagens a cada poucos segundos, o STANDARD (US$ 30/mês, 15 threads) ou o ADVANCE (US$ 90/mês, 50 threads) dão mais margem sem formar fila.
O monitoramento automatizado de leilões é detectável pelos sites?
A detecção depende do padrão das requisições, não da resolução do CAPTCHA em si. Use intervalos realistas entre as chamadas, alterne user agents e evite concentrar toda a atividade nos horários de menor tráfego, quando o seu volume se destaca no meio do silêncio.
Preciso resolver o CAPTCHA antes de cada requisição ou só quando ele aparece?
Só quando ele aparece. O padrão recomendado é enviar a requisição normalmente e resolver o CAPTCHA apenas se a resposta contiver o desafio — é o que o método _has_captcha() do exemplo em Python faz. Resolver de forma preventiva a cada chamada gasta threads sem necessidade.
O CaptchaAI resolve outros tipos de CAPTCHA além do reCAPTCHA v2 em sites de leilão?
Sim. A navegação por categorias em alguns sites de leilão aciona o Cloudflare Turnstile em vez do reCAPTCHA v2, e a CaptchaAI resolve os dois tipos com a mesma chave de API — só muda o parâmetro method na chamada a in.php.
Artigos relacionados
- Como resolver o callback do reCAPTCHA v2 pela API
- reCAPTCHA v2 e Cloudflare Turnstile no mesmo site
- Como funciona o callback do reCAPTCHA v2
Próximas etapas
Monitore leilões de forma confiável: crie sua chave de API da CaptchaAI e comece a resolver os desafios de reCAPTCHA v2 automaticamente.