Casos de Uso

Automatización de pago en varios pasos con resolución CAPTCHA

Automatice los flujos completos de pago: carrito, envío, pago, confirmación, manejando CAPTCHA en cada etapa.


Dónde aparecen los CAPTCHA en el proceso de pago

etapa Tipos comunes de CAPTCHA gatillo
Añadir al carrito reCAPTCHA v3 (invisible) Prevención de robots
Iniciar sesión/guest finalizar compra reCAPTCHA v2 Verificación de cuenta
Dirección de envío torniquete Limitación de velocidad
pagina de pago reCAPTCHA v2/v3 Prevención de fraude
Confirmación de pedido reCAPTCHA v2 Validación final

Arquitectura

┌────────┐    ┌───────────┐    ┌──────────┐    ┌─────────┐    ┌──────────┐
│  Cart  │───▶│  Shipping │───▶│ Payment  │───▶│ Review  │───▶│ Confirm  │
│        │    │  Address  │    │  Info    │    │  Order  │    │          │
└────────┘    └───────────┘    └──────────┘    └─────────┘    └──────────┘
     │              │               │               │              │
     ▼              ▼               ▼               ▼              ▼
  [CAPTCHA?]    [CAPTCHA?]     [CAPTCHA?]      [CAPTCHA?]     [CAPTCHA?]

Implementación central

Automatizador de pago

import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class CaptchaSolver:
    BASE = "https://ocr.captchaai.com"

    def __init__(self, api_key):
        self.api_key = api_key

    def solve(self, params, initial_wait=10):
        params["key"] = self.api_key
        params["json"] = 1
        resp = requests.post(f"{self.BASE}/in.php", data=params).json()
        if resp["status"] != 1:
            raise Exception(resp["request"])
        task_id = resp["request"]
        time.sleep(initial_wait)
        for _ in range(60):
            result = requests.get(
                f"{self.BASE}/res.php",
                params={"key": self.api_key, "action": "get", "id": task_id, "json": 1},
            ).json()
            if result["request"] == "CAPCHA_NOT_READY":
                time.sleep(5)
                continue
            if result["status"] == 1:
                return result["request"]
            raise Exception(result["request"])
        raise TimeoutError("Timed out")

class CheckoutAutomator:
    def __init__(self, api_key):
        self.solver = CaptchaSolver(api_key)
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver, 15)

    def _find(self, selector):
        return self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector)))

    def _click(self, selector):
        self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, selector))).click()

    def _fill(self, selector, value):
        el = self._find(selector)
        el.clear()
        el.send_keys(value)

    def _solve_if_captcha(self):
        """Check for and solve any CAPTCHA on the current page."""
        html = self.driver.page_source
        page_url = self.driver.current_url

        # Turnstile
        turnstile = self.driver.find_elements(By.CSS_SELECTOR, ".cf-turnstile")
        if turnstile:
            sitekey = turnstile[0].get_attribute("data-sitekey")
            token = self.solver.solve({
                "method": "turnstile",
                "sitekey": sitekey,
                "pageurl": page_url,
            })
            self.driver.execute_script(
                f'document.querySelector("[name=cf-turnstile-response]").value = "{token}";'
            )
            return "turnstile"

        # reCAPTCHA
        recaptcha = self.driver.find_elements(By.CSS_SELECTOR, "[data-sitekey]")
        if recaptcha and "recaptcha" in html.lower():
            sitekey = recaptcha[0].get_attribute("data-sitekey")

            # Check if v3 (invisible)
            if "grecaptcha.execute" in html:
                token = self.solver.solve({
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": page_url,
                    "version": "v3",
                    "action": "checkout",
                }, initial_wait=20)
            else:
                token = self.solver.solve({
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": page_url,
                })

            self.driver.execute_script(
                f'document.querySelector("[name=g-recaptcha-response]").value = "{token}";'
            )
            return "recaptcha"

        return None

    # --- Checkout Steps ---

    def add_to_cart(self, product_url, quantity=1):
        """Step 1: Navigate to product and add to cart."""
        self.driver.get(product_url)
        time.sleep(2)

        # Set quantity if field exists
        qty_fields = self.driver.find_elements(By.CSS_SELECTOR, "input[name='quantity']")
        if qty_fields:
            qty_fields[0].clear()
            qty_fields[0].send_keys(str(quantity))

        self._solve_if_captcha()
        self._click("[data-action='add-to-cart'], .add-to-cart, #add-to-cart")
        time.sleep(2)
        return True

    def fill_shipping(self, address):
        """Step 2: Fill shipping address."""
        self._solve_if_captcha()

        field_map = {
            "first_name": "#shipping-first-name, [name='firstName']",
            "last_name": "#shipping-last-name, [name='lastName']",
            "address": "#shipping-address, [name='address1']",
            "city": "#shipping-city, [name='city']",
            "state": "#shipping-state, [name='state']",
            "zip": "#shipping-zip, [name='postalCode']",
            "phone": "#shipping-phone, [name='phone']",
        }

        for field, selectors in field_map.items():
            if field in address:
                for selector in selectors.split(", "):
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    if elements:
                        elements[0].clear()
                        elements[0].send_keys(address[field])
                        break

        self._solve_if_captcha()
        self._click("[data-step='shipping-submit'], .continue-to-payment")
        time.sleep(2)
        return True

    def fill_payment(self, payment):
        """Step 3: Fill payment information."""
        self._solve_if_captcha()

        # Handle iframe for card fields (common pattern)
        iframes = self.driver.find_elements(By.CSS_SELECTOR, "iframe[name*='card']")
        if iframes:
            self.driver.switch_to.frame(iframes[0])
            self._fill("input[name='cardnumber']", payment["card_number"])
            self.driver.switch_to.default_content()

            if len(iframes) > 1:
                self.driver.switch_to.frame(iframes[1])
                self._fill("input[name='exp-date']", payment["expiry"])
                self.driver.switch_to.default_content()

            if len(iframes) > 2:
                self.driver.switch_to.frame(iframes[2])
                self._fill("input[name='cvc']", payment["cvv"])
                self.driver.switch_to.default_content()
        else:
            # Direct fields
            self._fill("[name='cardNumber'], #card-number", payment["card_number"])
            self._fill("[name='expiry'], #card-expiry", payment["expiry"])
            self._fill("[name='cvv'], #card-cvv", payment["cvv"])

        self._solve_if_captcha()
        self._click("[data-step='payment-submit'], .continue-to-review")
        time.sleep(2)
        return True

    def confirm_order(self):
        """Step 4: Review and confirm order."""
        self._solve_if_captcha()
        self._click("[data-step='confirm'], .place-order, #place-order")
        time.sleep(3)

        # Check for confirmation
        html = self.driver.page_source.lower()
        if "order confirmed" in html or "thank you" in html or "confirmation" in html:
            return True
        return False

    def run_checkout(self, product_url, address, payment, quantity=1):
        """Run complete checkout flow."""
        steps = [
            ("Add to cart", lambda: self.add_to_cart(product_url, quantity)),
            ("Proceed to checkout", lambda: self._click(".checkout-btn, a[href*='checkout']")),
            ("Fill shipping", lambda: self.fill_shipping(address)),
            ("Fill payment", lambda: self.fill_payment(payment)),
            ("Confirm order", lambda: self.confirm_order()),
        ]

        for step_name, step_fn in steps:
            print(f"Step: {step_name}...")
            try:
                result = step_fn()
                print(f"  ✓ {step_name} complete")
            except Exception as e:
                print(f"  ✗ {step_name} failed: {e}")
                return False
        return True

    def close(self):
        self.driver.quit()

Uso

automator = CheckoutAutomator("YOUR_API_KEY")

try:
    success = automator.run_checkout(
        product_url="https://store.example.com/product/widget-pro",
        address={
            "first_name": "Jane",
            "last_name": "Smith",
            "address": "123 Test Street",
            "city": "San Francisco",
            "state": "CA",
            "zip": "94102",
            "phone": "415-555-0100",
        },
        payment={
            "card_number": "4111111111111111",
            "expiry": "12/26",
            "cvv": "123",
        },
        quantity=1,
    )
    print(f"Checkout {'succeeded' if success else 'failed'}")
finally:
    automator.close()

Manejo de casos extremos

CAPTCHA aparece después de un error de validación

def retry_step_with_captcha(self, step_fn, max_retries=2):
    for attempt in range(max_retries + 1):
        try:
            return step_fn()
        except Exception:
            if attempt < max_retries:
                self._solve_if_captcha()
                continue
            raise

CAPTCHA basados en sesiones

Algunos sitios solo muestran CAPTCHA en la primera solicitud por sesión. Utilice cookies del navegador para mantener sesiones en todos los pasos.

Campos de formulario dinámicos

def wait_for_step(self, indicator_selector, timeout=15):
    """Wait for a step to fully load before proceeding."""
    WebDriverWait(self.driver, timeout).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, indicator_selector))
    )

Solución de problemas

Problema causa Solución
Token CAPTCHA rechazado en el pago Token caducado Resuelva CAPTCHA inmediatamente antes de hacer clic en enviar
Los campos de la tarjeta no se llenan iframe raya/Braintree Cambiar a iframe antes de llenar
Redirecciones de pago para iniciar sesión La sesión expiró Agregar paso de inicio de sesión antes de pagar
El pedido falla silenciosamente Faltan campos obligatorios Compruebe si hay mensajes de error después de cada paso

Preguntas frecuentes

¿Puedo probar los flujos de pago sin pagos reales?

Sí. La mayoría de las plataformas de comercio electrónico tienen modos sandbox/test con números de tarjeta de prueba. CaptchaAI resuelve los mismos CAPTCHA en entornos de prueba.

¿Cómo manejo los diferentes diseños de pago?

Utilice el patrón alternativo del selector CSS (selector1, selector2) para hacer coincidir las variaciones comunes. Personalice selectores para sitios específicos.

¿Qué pasa con los pagos de una página?

Adapte el flujo para completar todos los campos en una página y llame a _solve_if_captcha() una vez antes del envío final.


Guías relacionadas


Automatizar las pruebas de pago:manejar CAPTCHA con CaptchaAI.

Los comentarios están deshabilitados para este artículo.