Las plataformas de subastas protegen los datos de los listados y la funcionalidad de búsqueda con reCAPTCHA v2. Los CAPTCHA aparecen con mayor frecuencia durante consultas de búsqueda rápida, vistas detalladas de listados y búsquedas del historial de ofertas. A continuación se explica cómo mantener un seguimiento fiable en todos los sitios de subastas.
Dónde se activan los CAPTCHA en los sitios de subastas
| Acción | Tipo CAPTCHA | Patrón de disparo |
|---|---|---|
| Buscar listados de /browse | reCAPTCHA v2 | Búsquedas secuenciales rápidas |
| Ver detalles del listado | reCAPTCHA v2 | Alto volumen desde la misma IP |
| Consultar el historial de ofertas | reCAPTCHA v2 | Cargas repetidas de la página de detalles |
| Navegación por categorías | Cloudflare Turnstile | Velocidad de navegación similar a la de un bot |
| Páginas de alerta de precios | reCAPTCHA v2 | Actualizaciones frecuentes |
Monitoreo de subastas con resolución CAPTCHA
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"
)
Sistema de Alerta de Precios (JavaScript)
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();
Estrategia de seguimiento
| Verificar frecuencia | Caso de uso | Tasa CAPTCHA esperada |
|---|---|---|
| Cada 30 segundos | Ofertas de última hora | Alto: usar proxies |
| Cada 5 minutos | Seguimiento activo de subastas | Moderado |
| Cada 15 minutos | Monitoreo de lista de vigilancia | Bajo |
| Cada hora | Investigación de precios a largo plazo | Mínimo |
Reducir la frecuencia de CAPTCHA
| Técnica | Impacto |
|---|---|
| Reutilizar cookies de sesión | Mantiene el estado autenticado |
| Rotar proxies residenciales | Distribuye solicitudes entre IPs |
| Aleatorizar los intervalos de solicitud | Evita patrones de detección periódicos |
| Utilice cuentas autenticadas | Umbrales de activación de CAPTCHA más bajos |
Solución de problemas
| Problema | Causa | Solución |
|---|---|---|
| CAPTCHA en cada solicitud | Sin persistencia de sesión | Reutilizar requests.Session() |
| token reCAPTCHA rechazado | Token caducado (vida útil de 2 minutos) | Resolver justo antes del envío. |
| La página de listados muestra 0 resultados | CAPTCHA resultados filtrados silenciosamente | Compruebe si hay elementos CAPTCHA ocultos |
| IP bloqueada después de muchos CAPTCHA | Límite de tarifa excedido | Rotar proxies, aumentar intervalos |
Preguntas frecuentes
¿Qué tan rápido puedo consultar los listados de subastas?
CaptchaAI resuelve reCAPTCHA v2 en 10 a 30 segundos. Para subastas urgentes, resuelva previamente los tokens y rote los proxies para minimizar los retrasos.
¿Los sitios de subastas detectarán el seguimiento?
La detección depende de los patrones de solicitud, no de la resolución de CAPTCHA. Utilice intervalos realistas, rote los agentes de usuario y evite el scraping durante las horas de poco tráfico cuando sus solicitudes se destacan.
¿Puedo monitorear las subastas en vivo en tiempo real?
Durante los últimos minutos de una subasta, utilice la automatización del navegador con sesiones previamente autenticadas para minimizar los encuentros con CAPTCHA. La velocidad de CaptchaAI maneja cualquier CAPTCHA que aún aparezca.
Artículos relacionados
- Cómo resolver reCAPTCHA v2 con callback
- reCAPTCHA v2 y Turnstile en el mismo sitio
- Mecanismo de callback de reCAPTCHA v2
Supervisa las subastas de forma fiable: obtén tu API key de CaptchaAI y resuelve los desafíos reCAPTCHA v2 automáticamente.