Las plataformas de comercio electrónico protegen las páginas de productos y los datos de inventario con CAPTCHA para evitar el scraping de la competencia y las compras de bots. CaptchaAI permite el seguimiento automatizado de existencias, el seguimiento de precios y las alertas de disponibilidad.
CAPTCHA en plataformas de comercio electrónico
| Plataforma | Tipo CAPTCHA | Desencadenar | Datos |
|---|---|---|---|
| Amazonas | reCAPTCHA v2 | Acceso de gran volumen | Precio, stock, reseñas. |
| Walmart | reCAPTCHA v3 + Nubeflare | Detección de robots | inventario, precios |
| Mejor compra | reCAPTCHA v2 | Verificación de agregar al carrito | Stock, precios |
| Objetivo | Cloudflare Turnstile | Acceso automatizado | Disponibilidad |
| Tiendas Shopify | Cloudflare Turnstile | Limitación de velocidad | Datos del producto |
| eBay | reCAPTCHA v2 | Búsqueda + acceso al listado | Listados, precios |
Monitor de producto
import requests
import time
import re
import json
from datetime import datetime
from bs4 import BeautifulSoup
CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"
def solve_captcha(method, sitekey, pageurl, **kwargs):
data = {
"key": CAPTCHAAI_KEY, "method": method,
"googlekey": sitekey, "pageurl": pageurl, "json": 1,
}
data.update(kwargs)
resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=data)
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(5)
result = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
"key": CAPTCHAAI_KEY, "action": "get",
"id": task_id, "json": 1,
})
r = result.json()
if r["request"] != "CAPCHA_NOT_READY":
return r["request"]
raise TimeoutError("Timeout")
class RetailMonitor:
def __init__(self, proxy=None):
self.session = requests.Session()
if proxy:
self.session.proxies = {"http": proxy, "https": proxy}
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
})
def check_product(self, url):
"""Check single product's price and availability."""
resp = self.session.get(url, timeout=30)
# Handle CAPTCHA
if self._has_captcha(resp.text):
resp = self._solve_and_retry(resp.text, url)
soup = BeautifulSoup(resp.text, "html.parser")
return {
"url": url,
"title": self._text(soup, "h1, .product-title, #productTitle"),
"price": self._text(soup, ".price, .a-price .a-offscreen, .prod-price"),
"availability": self._text(soup, "#availability, .stock-status, .fulfillment"),
"in_stock": self._check_stock(soup),
"timestamp": datetime.now().isoformat(),
}
def monitor_products(self, product_urls, interval_sec=1800):
"""Continuously monitor products for changes."""
history = {}
while True:
for url in product_urls:
try:
current = self.check_product(url)
# Check for changes
prev = history.get(url)
if prev:
changes = self._detect_changes(prev, current)
if changes:
self._alert(current["title"], changes)
history[url] = current
time.sleep(3)
except Exception as e:
print(f"Error checking {url}: {e}")
print(f"Cycle complete: {len(product_urls)} products checked")
time.sleep(interval_sec)
def track_prices(self, product_urls, output_file="prices.json"):
"""Single price check across all products."""
results = []
for url in product_urls:
try:
data = self.check_product(url)
results.append(data)
time.sleep(3)
except Exception as e:
results.append({"url": url, "error": str(e)})
with open(output_file, "w") as f:
json.dump(results, f, indent=2)
print(f"Tracked {len(results)} products → {output_file}")
return results
def _has_captcha(self, html):
return any(tag in html.lower() for tag in [
'data-sitekey', 'g-recaptcha', 'cf-turnstile', 'captcha',
])
def _solve_and_retry(self, html, url):
match = re.search(r'data-sitekey="([^"]+)"', html)
if not match:
return self.session.get(url)
sitekey = match.group(1)
if 'cf-turnstile' in html:
token = solve_captcha("turnstile", sitekey, url)
return self.session.post(url, data={"cf-turnstile-response": token})
else:
token = solve_captcha("userrecaptcha", sitekey, url)
return self.session.post(url, data={"g-recaptcha-response": token})
def _text(self, soup, selector):
el = soup.select_one(selector)
return el.get_text(strip=True) if el else ""
def _check_stock(self, soup):
stock_el = soup.select_one("#availability, .stock-status")
if stock_el:
text = stock_el.get_text(strip=True).lower()
return "in stock" in text or "available" in text
return None
def _detect_changes(self, prev, current):
changes = []
if prev["price"] != current["price"]:
changes.append(f"Price: {prev['price']} → {current['price']}")
if prev["in_stock"] != current["in_stock"]:
status = "In Stock" if current["in_stock"] else "Out of Stock"
changes.append(f"Stock: → {status}")
return changes
def _alert(self, title, changes):
print(f"ALERT [{title}]: {', '.join(changes)}")
# Usage
monitor = RetailMonitor(
proxy="http://user:pass@residential.proxy.com:5000"
)
products = [
"https://store.example.com/product/abc123",
"https://store.example.com/product/def456",
"https://store.example.com/product/ghi789",
]
# One-time price check
results = monitor.track_prices(products)
# Or continuous monitoring (every 30 min)
# monitor.monitor_products(products, interval_sec=1800)
Escaneo de stock en toda la categoría
def scan_category(base_url, category, max_pages=20):
"""Scan an entire product category for stock status."""
monitor = RetailMonitor(
proxy="http://user:pass@residential.proxy.com:5000"
)
all_products = []
for page in range(1, max_pages + 1):
url = f"{base_url}/{category}?page={page}"
resp = monitor.session.get(url, timeout=30)
if monitor._has_captcha(resp.text):
resp = monitor._solve_and_retry(resp.text, url)
soup = BeautifulSoup(resp.text, "html.parser")
items = soup.select(".product-card, .s-result-item")
if not items:
break
for item in items:
all_products.append({
"name": monitor._text(item, ".product-name, .a-text-normal"),
"price": monitor._text(item, ".price, .a-price"),
"stock": monitor._text(item, ".stock, .a-color-success"),
"url": item.select_one("a")["href"] if item.select_one("a") else "",
})
time.sleep(3)
return all_products
Comparación de precios de la competencia
def compare_product_across_stores(product_name, stores):
"""Compare prices across retailers for the same product."""
results = []
for store in stores:
monitor = RetailMonitor(proxy=store.get("proxy"))
search_url = f"{store['base_url']}/search?q={product_name}"
try:
resp = monitor.session.get(search_url, timeout=30)
if monitor._has_captcha(resp.text):
resp = monitor._solve_and_retry(resp.text, search_url)
soup = BeautifulSoup(resp.text, "html.parser")
first_result = soup.select_one(".product-card, .s-result-item")
if first_result:
results.append({
"store": store["name"],
"price": monitor._text(first_result, ".price"),
"in_stock": "in stock" in first_result.get_text().lower(),
})
except Exception as e:
results.append({"store": store["name"], "error": str(e)})
time.sleep(5)
results.sort(key=lambda x: x.get("price", "zzzz"))
return results
Calendario de seguimiento
| Tipo de producto | Verificar frecuencia | Tipo de proxy |
|---|---|---|
| Electrónica | Cada 30 minutos | Residencial rotativo |
| Comestibles | Cada 4 horas | Residencial rotativo |
| Moda | Cada 2 horas | Residencial |
| Lanzamientos limitados | Cada 1 minuto | Red móvil autorizada |
| Artículos para el hogar | Cada 6 horas | Residencial |
| Bienes básicos | Cada 12 horas | Centro de datos (a menudo suficiente) |
Solución de problemas
| Asunto | Causa | Solución |
|---|---|---|
| CAPTCHA en cada página de producto | IP marcada o velocidad excedida | Aumentar el retraso, rotar los proxies |
| Precio incorrecto raspado | Precios dinámicos representados por JS | Utilice Selenium/Puppeteer en su lugar |
| Página "Comprobación del robot" | Detección de bots al estilo Amazon | Utilice encabezados realistas + red residencial autorizada |
| El stock muestra "no disponible" | Disponibilidad geográficamente restringida | Haga coincidir el proxy con la región de destino |
| Faltan datos del producto | La estructura de la página cambió. | Actualizar selectores CSS |
Preguntas frecuentes
¿Con qué frecuencia puedo consultar las páginas de productos?
Cada 30 a 60 minutos por producto es seguro para la mayoría de los minoristas. El monitoreo de mayor frecuencia (1-5 min) funciona pero requiere más servidores proxy y activa CAPTCHA.
¿Debo utilizar sesiones rotativas o fijas?
Rotación: cada página de producto es una solicitud independiente. Las sesiones fijas solo son necesarias si verificar los detalles del producto requiere navegación.
¿Puedo monitorear miles de productos?
Sí. Distribuya las solicitudes entre varias IP de proxy y escalone las comprobaciones. Con 1000 productos con retrasos de 3 segundos, un ciclo completo dura aproximadamente 50 minutos.
Guías relacionadas
- Representantes residenciales rotativos
- Sesiones fijas vs rotativas
- Monitoreo de la cadena de suministro
Seguimiento del inventario minorista en tiempo real.obtenga su clave CaptchaAIpara manejo automatizado de CAPTCHA.