ProductosIntegracionesRecursosDocumentaciónPrecios
Empezar ahora

© 2026 CapSolver. All rights reserved.

Contáctenos

Slack: lola@capsolver.com

Productos

  • reCAPTCHA v2
  • reCAPTCHA v3
  • Cloudflare Turnstile
  • Cloudflare Challenge
  • AWS WAF
  • Extensión de navegador
  • Más tipos de CAPTCHA

Integraciones

  • Selenium
  • Playwright
  • Puppeteer
  • n8n
  • Socios
  • Ver todas las integraciones

Recursos

  • Programa de referidos
  • Documentación
  • Referencia de API
  • Blog
  • Preguntas frecuentes
  • Glosario
  • Estado

Legal

  • Términos de servicio
  • Política de privacidad
  • Política de reembolso
  • No vender mi información personal
//Cómo crear scrapers para el scraping web en n8n con CapSolver
Apr03, 2026

Cómo crear scrapers para el scraping web en n8n con CapSolver

Aloísio Vítor

Aloísio Vítor

Image Processing Expert

Si alguna vez has intentado extraer precios, datos de productos o contenido de páginas protegidas, ya sabes que la parte difícil no es solo cargar la URL. El flujo de trabajo también debe resolver los captchas del sitio, enviar el token resuelto de la manera que el sitio espere y luego extraer los datos correctos de la respuesta protegida.

Es por eso que los ejemplos simples "resolver captchas y listo" no son suficientes para la automatización real. Un sitio puede esperar el token en un encabezado, en el cuerpo del formulario, en un payload JSON, en una cadena de consulta, en una cookie o en otro campo específico de la aplicación. Puede usar reCAPTCHA, Turnstile o otro desafío de captcha completamente diferente. Y una vez que regrese la respuesta protegida, los selectores y la lógica de salida aún deben coincidir con tu objetivo.

En esta guía, aprenderás a construir scrapers para sitios protegidos por captcha en n8n usando CapSolver. La explicación principal se basa en el flujo de trabajo del repositorio Scraping — Price & Product Details — CapSolver + Schedule + Webhook, pero el mismo patrón se puede adaptar para:

  • extraer precios y datos de productos
  • verificar cambios en el stock o contenido protegido
  • iniciar sesión en tu propia cuenta
  • activar una extracción de objetivo fijo desde otro servicio a través de un webhook

Este artículo trata sobre automatización práctica y autorizada en objetivos que posees, gestionas o estás autorizado a probar.

Importante: Estos flujos de trabajo son ejemplos y plantillas iniciales, no recetas universales. Debes esperar modificar la configuración de captcha, el método de envío del token, la carga de la solicitud, los encabezados, las cookies, los selectores y la lógica de salida para que coincidan con cada sitio específico.


Qué Construye Esta Guía

El ejemplo principal de este artículo es una plantilla de scraper para objetivos fijos que ahora soporta dos modos de activación:

  • Programación: se ejecuta automáticamente cada 6 horas
  • Webhook: activa el mismo objetivo configurado a demanda

En la plantilla predeterminada del repositorio, ese flujo de trabajo:

  • resuelve reCAPTCHA v3
  • obtiene una página de producto protegida
  • envía el token a través del encabezado x-recaptcha-token
  • extrae price y productName
  • compara el valor actual con $workflow.staticData
  • devuelve un payload de alerta o un payload sin cambios

El mismo patrón puede convertirse en:

  • un scraper
  • un scraper de detalles de producto
  • un verificador de stock
  • un flujo de inicio de sesión para tu propia cuenta

Casos de Uso Comunes

Todas las plantillas de este repositorio siguen el mismo esqueleto reutilizable:

activación -> resolver captchas -> enviar solicitud protegida -> extraer resultado -> comparar/guardar/salida

Esta estructura se adapta a varios casos de uso legítimos:

Caso de uso ¿Qué cambia?
Extracción de datos Extraer campos de precio y compararlos con el tiempo
Extracción de datos de productos Extraer campos como título, SKU, vendedor, stock o descripción
Verificación de stock Comparar texto de disponibilidad, cantidad o estado del botón de compra
Inicio de sesión en tu propia cuenta Enviar el token resuelto con tu solicitud de inicio de sesión y verificar el éxito
Recuperación de contenido protegido Obtener contenido restringido y devolver los campos extraídos
Extracción disparada por webhook Deja que otro servicio active el objetivo configurado fijo a demanda

La estructura sigue siendo reutilizable, pero los detalles de implementación reales pueden variar en cada sitio. En la práctica, los usuarios deben tratar cada flujo de trabajo aquí como un ejemplo y luego adaptar la configuración de resolución, la forma de la solicitud, la ubicación del token y la lógica de extracción al objetivo que están automatizando.


Flujo de Trabajo: Ejemplos de Casos de Uso

El flujo de trabajo principal anterior recupera contenido de página sin procesar y compara precios. Los siguientes flujos extienden el mismo patrón de resolución de captcha — Activación → Resolver Captcha → Enviar Solicitud Protegida → Evaluar Resultado — a casos de uso específicos. Cada uno requiere los mismos requisitos previos: una instancia de n8n, una credencial de CapSolver y los parámetros de captcha del objetivo.

Flujo de trabajo Propósito
Scraping — Price & Product Details — CapSolver + Schedule + Webhook Plantilla de programación + webhook para objetivos fijos que resuelve reCAPTCHA v3, envía el token en x-recaptcha-token, extrae price y productName, compara valores con $workflow.staticData y puede usarse para extracción, extracción de detalles de producto o verificaciones similares en páginas protegidas de productos

Nota de activación: Esta plantilla se importa como active: false. La ruta del webhook no está activa hasta que configures los marcadores de posición, elige tu credencial de CapSolver y activas el flujo de trabajo en n8n.


Requisitos Previos

Antes de comenzar, asegúrate de tener:

  1. Una instancia de n8n
  2. Una cuenta de CapSolver con clave de API y saldo
  3. Un nodo de CapSolver configurado en n8n
  4. Una URL de objetivo y los campos que deseas extraer
  5. Los parámetros de captcha requeridos por ese objetivo
  6. Una comprensión clara de cómo se envía realmente la solicitud protegida en el navegador

Para el ejemplo principal de este artículo, se asume que el objetivo utiliza reCAPTCHA, por lo que los valores clave son:

  • websiteURL
  • websiteKey
  • pageAction para reCAPTCHA v3

Importante: El recorrido para identificar parámetros a continuación está intencionalmente limitado a ejemplos de reCAPTCHA. Los objetivos reales pueden usar un tipo de desafío completamente diferente, como Cloudflare Turnstile, Cloudflare Challenge, GeeTest, DataDome, AWS WAF o MTCaptcha, y en ese caso la configuración del nodo de resolución, los campos requeridos y el patrón de solicitud protegida serán diferentes.


Cómo Identificar los Parámetros de reCAPTCHA

Para páginas protegidas por reCAPTCHA, los valores principales suelen ser:

Parámetro Qué significa
websiteURL La URL donde se muestra o se requiere el captcha
websiteKey La clave pública utilizada por la página
pageAction La cadena de acción esperada por reCAPTCHA v3

En la plantilla de monitoreo de precios del repositorio, el nodo de CapSolver está configurado con:

  • operation: reCAPTCHA v3
  • websiteURL: https://YOUR-TARGET-SITE.com/product-page
  • websiteKey: YOUR_SITE_KEY_HERE
  • pageAction: view_product

Al inspeccionar un objetivo de reCAPTCHA, verifica:

  • qué versión de reCAPTCHA utiliza
  • si se requiere pageAction
  • dónde se envía realmente el token resuelto

Importante: Esta no es una sección de detección de captchas universal. Si el objetivo utiliza un tipo de desafío diferente, como Cloudflare Turnstile, Cloudflare Challenge, GeeTest, DataDome, AWS WAF o MTCaptcha, deberás cambiar tanto la configuración de CapSolver como la solicitud HTTP que envía el token resuelto.


Flujo de Trabajo Principal: Scraping — Price & Product Details — CapSolver + Schedule + Webhook

El flujo de trabajo del repositorio Scraping — Price & Product Details — CapSolver + Schedule + Webhook ahora soporta dos caminos de activación para objetivos fijos:

  • Cada 6 horas para revisiones recurrentes
  • Webhook Trigger para ejecuciones a demanda

Ambos caminos usan los mismos marcadores de posición de objetivo y la misma lógica de scraper. La versión de webhook simplemente termina en Respond to Webhook para que el llamador obtenga el payload de alerta final o el payload sin cambios como JSON.

Camino de Programación

El camino de programación usa estos nodos:

  1. Every 6 Hours
  2. Solve reCAPTCHA v3
  3. Fetch Product Page
  4. Extract Data
  5. Compare Data
  6. Data Changed?
  7. Build Alert
  8. No Change

Camino de Webhook

El camino de webhook duplica la misma lógica para el mismo objetivo fijo:

  1. Webhook Trigger
  2. Solve reCAPTCHA v3 [Webhook]
  3. Fetch Product Page [Webhook]
  4. Extract Data [Webhook]
  5. Compare Data [Webhook]
  6. Data Changed? [Webhook]
  7. Build Alert [Webhook]
  8. No Change [Webhook]
  9. Respond to Webhook

Cómo Funciona la Lógica Principal

1. Activación

Usa programación cuando quieres revisiones recurrentes, como extracción o verificación de stock.

Usa webhook cuando otro flujo de trabajo, servicio o aplicación debe activar el mismo objetivo configurado a demanda.

2. Resolver reCAPTCHA v3

La plantilla usa:

Configuración Valor
Operación reCAPTCHA v3
websiteURL https://YOUR-TARGET-SITE.com/product-page
websiteKey YOUR_SITE_KEY_HERE
pageAction view_product

3. Obtener la Página Protegida

El token resuelto se envía en un encabezado de solicitud:

Encabezado Valor
user-agent Agente de usuario estilo navegador
x-recaptcha-token {{ $json.data.solution.gRecaptchaResponse }}

Este es uno de los detalles más importantes del flujo de trabajo. La plantilla del repositorio no asume que el token siempre pertenezca a g-recaptcha-response. En este ejemplo, va en un encabezado personalizado.

4. Extraer price y productName

El nodo HTML extrae:

Clave Selector CSS
price .product-price, [data-price], .price
productName h1, .product-title

5. Comparar con Ejecuciones Anteriores

El nodo Code almacena y compara valores usando:

  • $workflow.staticData.lastPrice
  • $workflow.staticData.lastChecked

Esto permite que el flujo de trabajo distinga entre:

  • primera verificación
  • sin cambios
  • aumento de precio
  • disminución de precio

6. Ramificar a Alerta o Sin Cambio

El nodo IF comprueba {{ $json.changed }}.

Si el precio cambió, el flujo de trabajo va a Build Alert.

Si no, va a No Change.

En el camino de webhook, cualquiera de las ramas luego entra en Respond to Webhook.


Por Qué Esto Es Realmente una Plantilla de Scraper

Aunque el ejemplo principal incluye lógica de comparación de precios, es más útil pensar en él como una plantilla de scraper para páginas de productos protegidas con lógica de comparación.

Las partes reutilizables son:

  • el modo de activación
  • el tipo de captcha
  • la configuración de resolución
  • la solicitud protegida
  • los selectores de extracción
  • la lógica de comparación o salida

Es por eso que la misma estructura puede impulsar:

  • extracción
  • extracción de detalles de producto
  • verificación de stock
  • validación de página protegida
  • verificación de inicio de sesión para tu propia cuenta

Lo Que Probablemente Necesites Cambiar

Esta es la parte que importa más en un objetivo real.

Para la mayoría de los sitios reales, deberías asumir que casi todo aquí es ajustable: el tipo de desafío, los parámetros de resolución, dónde se envía el token, el cuerpo de la solicitud, las cookies, los encabezados, los selectores y hasta los criterios de éxito final. Estos flujos de trabajo del repositorio son ejemplos de patrones funcionales, no recetas fijas que se ajusten a cada sitio sin cambios.

1. Modo de Activación

Los flujos de uso del repositorio ahora soportan programación + webhook.

Usa:

  • programación para revisiones recurrentes
  • webhook para activación a demanda desde otro servicio

Los caminos de webhook en estas plantillas son activadores de objetivos fijos, no APIs públicas para objetivos proporcionados por usuarios.

2. Tipo de CAPTCHA

El ejemplo principal de monitoreo de precios usa reCAPTCHA v3, pero tu objetivo puede usar:

  • reCAPTCHA v2
  • reCAPTCHA v3
  • Cloudflare Turnstile
  • Cloudflare Challenge
  • GeeTest V3 / V4
  • DataDome
  • AWS WAF
  • MTCaptcha
  • otro tipo de desafío soportado

Si esto cambia, deberás actualizar el paso de resolución en consecuencia.

3. Configuración de Resolución de CAPTCHA

Incluso cuando dos sitios usan reCAPTCHA, las configuraciones aún pueden diferir.

Es posible que debas cambiar:

  • la operación o tipo de tarea de CapSolver
  • websiteURL
  • websiteKey
  • pageAction
  • opciones relacionadas con invisible/empresarial
  • cualquier otro ajuste de desafío específico del sitio

La plantilla de scraper expone estos como campos de configuración de marcador de posición porque se espera que cambien.

4. Dónde Se Envía el Token

No asumas que el token siempre va al mismo lugar.

Este repositorio ya muestra varios patrones:

Patrón Ejemplo del repositorio
Encabezado de solicitud Scraping — CapSolver + Schedule usa x-recaptcha-token
Cuerpo del formulario Los flujos de inicio de sesión suelen usar g-recaptcha-response en un cuerpo codificado como formulario

En sitios reales, el token resuelto puede pertenecer a:

  • un encabezado
  • un campo de formulario
  • un payload JSON
  • un parámetro de consulta
  • una cookie
  • un campo oculto
  • otro valor específico de la aplicación

Este ejemplo del repositorio es un patrón de envío, no uno universal.

5. La Propia Solicitud Protegida

La solicitud protegida puede requerir más que solo el token de captcha o desafío.

Es posible que debas ajustar:

  • encabezados
  • cookies
  • valores CSRF
  • campos ocultos
  • codificación de formulario
  • forma del cuerpo JSON
  • método de solicitud

Eso es especialmente común para:

  • flujos de inicio de sesión
  • envíos de formulario de compra o restringidos

6. Lo Que Extraes

La plantilla principal de scraper extrae:

  • price
  • productName

Pero puedes reemplazarlo por:

  • título
  • estado de stock
  • SKU
  • descripción
  • valores de variantes
  • texto de disponibilidad
  • bloques completos de contenido protegido

7. Lo Que Comparas o Salidas

El código de monitoreo de precios actual compara valores numéricos, pero el mismo patrón se puede adaptar para:

  • cambio de precio
  • cambio de stock
  • éxito de inicio de sesión
  • éxito de registro
  • diferencia de contenido
  • estado de salud del sitio
  • exportación de datos sin comparación

Importar Este Flujo de Trabajo

El JSON a continuación es la versión importable actual de Scraping — Price & Product Details — CapSolver + Schedule + Webhook de este repositorio, incluyendo los caminos de programación + webhook.

Haz clic para expandir el JSON del flujo de trabajo
json Copy
{
  "nodes": [
    {
      "parameters": {
        "content": "## Scraping \u2014 Price & Product Monitor\n\n### How it works\n\n1. Triggers either by schedule or webhook input to start price monitoring.\n2. Solves reCAPTCHA to access the targeted product page.\n3. Retrieves and extracts data from the product page for further analysis.\n4. Compares newly fetched data with previously stored data to detect changes.\n5. Determines if changes occurred and prepares alerts if needed.\n6. Sends responses based on data analysis through designated channels.\n\n### Setup steps\n\n- [ ] Configure scheduled trigger interval in 'Every 6 Hours' node.\n- [ ] Set target website details in 'Set Target Config [Schedule]'.\n- [ ] Configure reCAPTCHA solver with API key in 'Solve reCAPTCHA v3' nodes.\n- [ ] Set up Webhook URL and path in 'Webhook Trigger'.\n- [ ] Define alert criteria and destination in 'Build Alert' nodes.\n\n### Customization\n\nAdjust the extraction pattern in 'Extract Data' nodes to fit specific product details.",
        "height": 896,
        "width": 480
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1328,
        -304
      ],
      "id": "52c7808e-d2bc-4779-85e6-909a51066338",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## Scheduled trigger setup\n\nInitializes the data monitoring process every 6 hours using a schedule trigger and sets the target configuration for scraping.",
        "height": 320,
        "width": 496,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -752,
        -160
      ],
      "id": "3c5cee67-552d-48ea-8717-7c5126269e2e",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
"content": "## Proceso de raspado programado\n\nResuelve reCAPTCHA, obtiene la página del producto, extrae los datos y los compara con los registros anteriores para identificar cambios, siguiendo un disparador programado.",
        "height": 496,
        "width": 1680,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -144,
        -304
      ],
      "id": "d0315be2-111c-4893-bf42-2f2cc2eb186f",
      "name": "Nota adhesiva2"
    },
    {
      "parameters": {
        "content": "## Configuración del disparador de webhook\n\nManeja la supervisión de datos activada manualmente a través de un webhook entrante y resuelve reCAPTCHA para continuar.",
        "height": 304,
        "width": 816,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -768,
        336
      ],
      "id": "a78f1606-07fb-40fd-af82-e1dc9b766206",
      "name": "Nota adhesiva3"
    },
    {
      "parameters": {
        "content": "## Proceso de raspado mediante webhook\n\nProcesa las solicitudes activadas por webhook obteniendo la página del producto, extrayendo los datos y determinando los cambios.",
        "height": 272,
        "width": 1088,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        160,
        320
      ],
      "id": "1a677fd9-a3a8-404f-ba9a-2b087d7bfe11",
      "name": "Nota adhesiva4"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -704,
        0
      ],
      "id": "sc-901",
      "name": "Cada 6 horas"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "websiteURL",
              "value": "https://TU-SITIO-OBJETIVO.com/pagina-del-producto",
              "type": "string"
            },
            {
              "id": "cfg-002",
              "name": "websiteKey",
              "value": "TU-CLAVE-DE-SITIO-AQUÍ",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -400,
        0
      ],
      "id": "sc-900",
      "name": "Establecer Configuración de destino [Programado]"
    },
    {
      "parameters": {
        "operation": "reCAPTCHA v3",
        "websiteURL": "={{ $json.websiteURL }}",
        "websiteKey": "={{ $json.websiteKey }}",
        "optional": {
          "pageAction": "ver_producto"
        }
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -96,
        0
      ],
      "id": "sc-902",
      "name": "Resolver reCAPTCHA v3",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Cuenta de CapSolver"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Establecer Configuración de destino [Programado]').first().json.websiteURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "x-recaptcha-token",
              "value": "={{ $json.data.solution.gRecaptchaResponse }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        208,
        0
      ],
      "id": "sc-903",
      "name": "Obtener Página del Producto"
    },
    {
      "parameters": {
        "operation": "extraerContenidoHtml",
        "extractionValues": {
          "values": [
            {
              "key": "price",
              "cssSelector": ".producto-precio, [data-precio], .precio"
            },
            {
              "key": "productName",
              "cssSelector": "h1, .titulo-del-producto"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        512,
        0
      ],
      "id": "sc-904",
      "name": "Extraer Datos"
    },
    {
      "parameters": {
        "jsCode": "const datosEstaticos = $workflow.staticData;\nconst precioActual = $input.first().json.price;\nconst precioAnterior = datosEstaticos.ultimoPrecio;\nconst nombreProducto = $input.first().json.productName || 'Producto';\nconst parsearPrecio = (cadena) => { if (!cadena) return null; const coincidencia = cadena.match(/[\\d,]+\\.?\\d*/); return coincidencia ? parseFloat(coincidencia[0].replace(',', '')) : null; };\nconst precioNumericoActual = parsearPrecio(precioActual);\nconst precioNumericoAnterior = parsearPrecio(precioAnterior);\ndatosEstaticos.ultimoPrecio = precioActual;\ndatosEstaticos.fechaUltimaVerificacion = new Date().toISOString();\nconst cambio = precioNumericoAnterior !== null && precioNumericoActual !== null && precioNumericoActual !== precioNumericoAnterior;\nconst direccion = cambio ? (precioNumericoActual < precioNumericoAnterior ? 'disminuyó' : 'aumentó') : 'sin cambios';\nconst diferencia = cambio ? Math.abs(precioNumericoActual - precioNumericoAnterior).toFixed(2) : '0';\nreturn [{ json: { nombreProducto, precioActual, precioAnterior: precioAnterior || 'primera verificación', cambio, direccion, diferencia: cambio ? `$${diferencia}` : null, fechaVerificacion: new Date().toISOString() } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        0
      ],
      "id": "sc-905",
      "name": "Comparar Datos"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "si-1",
              "leftValue": "={{ $json.cambio }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "y"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1104,
        0
      ],
      "id": "sc-906",
      "name": "¿Datos modificados?"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "alerta",
              "value": "=Precio {{ $json.direccion }} para {{ $json.nombreProducto }}: {{ $json.precioAnterior }} \u2192 {{ $json.precioActual }}",
              "type": "string"
            },
            {
              "id": "a2",
              "name": "severidad",
              "value": "={{ $json.direccion === 'disminuyó' ? 'oferta' : 'información' }}",
              "type": "string"
            },
            {
              "id": "a3",
              "name": "fechaVerificacion",
              "value": "={{ $json.fechaVerificacion }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1392,
        -192
      ],
      "id": "sc-907",
      "name": "Crear Alerta"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "n1",
              "name": "estado",
              "value": "sin_cambio",
              "type": "string"
            },
            {
              "id": "n2",
              "name": "precioActual",
              "value": "={{ $json.precioActual }}",
              "type": "string"
            },
            {
              "id": "n3",
              "name": "fechaVerificacion",
              "value": "={{ $json.fechaVerificacion }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1392,
        32
      ],
      "id": "sc-908",
      "name": "Sin Cambio"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "monitoreo-de-precios",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -720,
        464
      ],
      "id": "sc-909",
      "name": "Disparador de Webhook",
      "webhookId": "sc-909-webhook",
      "onError": "continuarSalidaRegular"
    },
    {
      "parameters": {
        "operation": "reCAPTCHA v3",
        "websiteURL": "={{ $json.body.websiteURL }}",
        "websiteKey": "={{ $json.body.websiteKey }}",
        "optional": {
          "pageAction": "={{ $json.body.pageAction || 'ver_producto' }}"
        }
      },
      "type": "n8n-nodes-capsolver.capSolver",
      "typeVersion": 1,
      "position": [
        -96,
        464
      ],
      "id": "sc-910",
      "name": "Resolver reCAPTCHA v3 [Webhook]",
      "credentials": {
        "capSolverApi": {
          "id": "BeBFMAsySMsMGeE9",
          "name": "Cuenta de CapSolver"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Disparador de Webhook').item.json.body.websiteURL }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "user-agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
            },
            {
              "name": "x-recaptcha-token",
              "value": "={{ $json.data.solution.gRecaptchaResponse }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        208,
        432
      ],
      "id": "sc-911",
      "name": "Obtener Página del Producto [Webhook]"
    },
    {
      "parameters": {
        "operation": "extraerContenidoHtml",
        "extractionValues": {
          "values": [
            {
              "key": "price",
              "cssSelector": ".producto-precio, [data-precio], .precio"
            },
            {
              "key": "productName",
              "cssSelector": "h1, .titulo-del-producto"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        512,
        432
      ],
      "id": "sc-912",
      "name": "Extraer Datos [Webhook]"
    },
    {
      "parameters": {
        "jsCode": "const datosEstaticos = $workflow.staticData;\nconst precioActual = $input.first().json.price;\nconst precioAnterior = datosEstaticos.ultimoPrecio;\nconst nombreProducto = $input.first().json.productName || 'Producto';\nconst parsearPrecio = (cadena) => { if (!cadena) return null; const coincidencia = cadena.match(/[\\d,]+\\.?\\d*/); return coincidencia ? parseFloat(coincidencia[0].replace(',', '')) : null; };\nconst precioNumericoActual = parsearPrecio(precioActual);\nconst precioNumericoAnterior = parsearPrecio(precioAnterior);\ndatosEstaticos.ultimoPrecio = precioActual;\ndatosEstaticos.fechaUltimaVerificacion = new Date().toISOString();\nconst cambio = precioNumericoAnterior !== null && precioNumericoActual !== null && precioNumericoActual !== precioNumericoAnterior;\nconst direccion = cambio ? (precioNumericoActual < precioNumericoAnterior ? 'disminuyó' : 'aumentó') : 'sin cambios';\nconst diferencia = cambio ? Math.abs(precioNumericoActual - precioNumericoAnterior).toFixed(2) : '0';\nreturn [{ json: { nombreProducto, precioActual, precioAnterior: precioAnterior || 'primera verificación', cambio, direccion, diferencia: cambio ? `$${diferencia}` : null, fechaVerificacion: new Date().toISOString() } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        432
      ],
      "id": "sc-913",
      "name": "Comparar Datos [Webhook]"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "si-2",
              "leftValue": "={{ $json.cambio }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "y"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1104,
        432
      ],
      "id": "sc-914",
      "name": "¿Datos modificados? [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a4",
              "name": "alerta",
              "value": "=Precio {{ $json.direccion }} para {{ $json.nombreProducto }}: {{ $json.precioAnterior }} \u2192 {{ $json.precioActual }}",
              "type": "string"
            },
            {
              "id": "a5",
              "name": "severidad",
              "value": "={{ $json.direccion === 'disminuyó' ? 'oferta' : 'información' }}",
              "type": "string"
            },
            {
              "id": "a6",
              "name": "fechaVerificacion",
              "value": "={{ $json.fechaVerificacion }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1424,
        384
      ],
      "id": "sc-915",
      "name": "Crear Alerta [Webhook]"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "n4",
              "name": "estado",
              "value": "sin_cambio",
              "type": "string"
            },
            {
              "id": "n5",
              "name": "precioActual",
              "value": "={{ $json.precioActual }}",
              "type": "string"
            },
            {
              "id": "n6",
              "name": "fechaVerificacion",
              "value": "={{ $json.fechaVerificacion }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1440,
        592
      ],
      "id": "sc-916",
      "name": "Sin Cambio [Webhook]"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        1712,
        512
      ],
      "id": "sc-917",
      "name": "Responder al Webhook"
    }
  ],
  "connections": {
    "Cada 6 horas": {
      "main": [
        [
          {
"node": "Configurar objetivo [Programar]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Configurar objetivo [Programar]": {
      "principal": [
        [
          {
            "node": "Resolver reCAPTCHA v3",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Resolver reCAPTCHA v3": {
      "principal": [
        [
          {
            "node": "Obtener página del producto",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Obtener página del producto": {
      "principal": [
        [
          {
            "node": "Extraer datos",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Extraer datos": {
      "principal": [
        [
          {
            "node": "Comparar datos",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Comparar datos": {
      "principal": [
        [
          {
            "node": "¿Datos cambiados?",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "¿Datos cambiados?": {
      "principal": [
        [
          {
            "node": "Crear alerta",
            "type": "principal",
            "index": 0
          }
        ],
        [
          {
            "node": "Sin cambios",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Disparador de webhook": {
      "principal": [
        [
          {
            "node": "Resolver reCAPTCHA v3 [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Resolver reCAPTCHA v3 [Webhook]": {
      "principal": [
        [
          {
            "node": "Obtener página del producto [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Obtener página del producto [Webhook]": {
      "principal": [
        [
          {
            "node": "Extraer datos [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Extraer datos [Webhook]": {
      "principal": [
        [
          {
            "node": "Comparar datos [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Comparar datos [Webhook]": {
      "principal": [
        [
          {
            "node": "¿Datos cambiados? [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "¿Datos cambiados? [Webhook]": {
      "principal": [
        [
          {
            "node": "Crear alerta [Webhook]",
            "type": "principal",
            "index": 0
          }
        ],
        [
          {
            "node": "Sin cambios [Webhook]",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Crear alerta [Webhook]": {
      "principal": [
        [
          {
            "node": "Responder al webhook",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    },
    "Sin cambios [Webhook]": {
      "principal": [
        [
          {
            "node": "Responder al webhook",
            "type": "principal",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
  }
}
``

</details>

---

## Prueba esto

Una vez que haya configurado los marcadores de posición y activado el flujo de trabajo, active la ruta del webhook:

```bash
curl -X POST https://your-n8n-instance.com/webhook/price-monitor \
  -H "Content-Type: application/json" \
  -d '{}'

Respuesta esperada (primera verificación):

json Copy
{
  "status": "no_change",
  "currentPrice": "$29.99",
  "checkedAt": "2026-03-11T08:00:00.000Z"
}

Respuesta esperada (precio cambiado):

json Copy
{
  "alert": "El precio ha bajado para Widget Pro: $39.99 → $29.99 (-$10.00)",
  "severity": "deal",
  "checkedAt": "2026-03-11T14:00:00.000Z"
}

Una respuesta con datos de precio reales confirma que todo el pipeline funcionó — captcha resuelto, página protegida obtenida, datos extraídos y lógica de comparación ejecutada.


Solución de problemas

Token resuelto, aún bloqueado

Si CapSolver devuelve un token pero el sitio sigue bloqueando la solicitud, el problema suele no ser la resolución en sí. Causas comunes:

  • tipo de captcha incorrecto
  • configuración de resolución incorrecta
  • valor incorrecto de pageAction
  • token enviado en el lugar incorrecto
  • cookies, encabezados o campos ocultos faltantes

El sitio utiliza un tipo de desafío diferente

Si el objetivo utiliza un desafío no reCAPTCHA — como Cloudflare Turnstile, Cloudflare Challenge, GeeTest, DataDome, AWS WAF o MTCaptcha — el ejemplo principal no funcionará sin cambios. Debe actualizar:

  • la configuración del nodo CapSolver
  • los parámetros de desafío esperados
  • la solicitud protegida que envía el token

Los selectores devuelven nada

Si el nodo HTML no extrae los campos que espera:

  • verifique si realmente recibe la página protegida
  • confirme los selectores contra el HTML devuelto
  • asegúrese de que los datos estén presentes en la respuesta cruda y no solo después de la renderización del lado del cliente

El webhook no funciona

Las plantillas del repositorio se importan como inactivas. Hasta que:

  1. configure los marcadores de posición
  2. elija credenciales
  3. active el flujo de trabajo

la ruta del webhook no estará activa.


Mejores prácticas

  1. Use el token inmediatamente después de resolverlo.
  2. Inspeccione la solicitud exacta del navegador antes de copiarla en n8n.
  3. Asuma que cada objetivo puede necesitar configuraciones de resolución diferentes.
  4. Asume que cada objetivo puede necesitar lógica de envío diferente.
  5. Verifique la respuesta protegida antes de depurar los selectores.
  6. Trate las plantillas del repositorio como puntos de partida, no como soluciones universales.
  7. Mantenga las plantillas de webhook con objetivo fijo, a menos que tenga una razón para exponer más.
  8. Pruebe el ciclo completo de resolver -> enviar -> extraer, no solo el paso de resolver.
  9. Agregue nodos de notificación o almacenamiento posterior después de Crear alerta o los nodos de éxito/fallo de autenticación.

¿Listo para comenzar? Regístrese en CapSolver y use el código de bonificación OPENCLAW para obtener un 6% adicional en su primer recarga!


Conclusión

La lección principal es simple: resolver captchas es solo un paso en el flujo de trabajo. El raspador real aún debe enviar el token correctamente, enviar la forma de solicitud adecuada y extraer los campos que importan para su caso de uso.

Eso también es por qué estas plantillas deben tratarse como ejemplos. Un sitio diferente puede utilizar un tipo de captcha diferente, esperar el token en otro lugar, necesitar cookies o campos adicionales, devolver una forma de respuesta diferente y requerir lógica de extracción o validación diferente.

Esta plantilla le da un punto de partida para:

  • raspado o extracción de datos
  • monitoreo de productos
  • verificación de existencias
  • recuperación de contenido protegido

Utiliza el patrón general:

disparador -> resolver captchas -> enviar solicitud protegida -> extraer o verificar resultado -> salida

Configure los marcadores de posición, mantenga los flujos inactivos hasta que coincidan con su objetivo y luego active la ruta de programación o webhook que se adapte a su caso de uso.


Preguntas frecuentes

¿Puedo usar esto para iniciar sesión en mi propia cuenta?

La plantilla de raspador se puede adaptar para flujos de inicio de sesión cambiando el nodo HTTP Request para enviar credenciales junto con el token resuelto. Consulte las guías dedicadas a tipos de captcha (reCAPTCHA, Turnstile, etc.) para plantillas de flujo de trabajo de inicio de sesión listas.

¿Qué pasa si el sitio utiliza un tipo de desafío diferente?

Entonces debe modificar el flujo de trabajo. Las configuraciones de reCAPTCHA y el patrón de solicitud del ejemplo principal no son universales. CapSolver admite Cloudflare Turnstile, Cloudflare Challenge, GeeTest V3/V4, DataDome, AWS WAF, MTCaptcha y otros. Actualice el paso de resolución de CapSolver y la solicitud protegida para que coincidan con el tipo de desafío real y el patrón de envío de token utilizado por el objetivo.

¿Dónde debo enviar el token?

Donde el sitio objetivo lo espera. Podría ser:

  • un encabezado
  • el cuerpo de un formulario
  • un payload JSON
  • un parámetro de consulta
  • una cookie
  • un campo oculto

La plantilla de monitoreo de precios utiliza un encabezado. Otros sitios variarán.

¿Necesito cambiar la configuración de CapSolver para cada sitio?

Normalmente, sí. Incluso los sitios que utilizan la misma familia de captchas pueden requerir diferentes websiteURL, websiteKey, pageAction, configuraciones invisibles u otras opciones de tarea.

¿Puedo raspar algo diferente al precio?

Sí. Cambie los selectores y la lógica de salida según lo que necesite, como existencias, título, SKU, descripción, contenido protegido, estado de inicio de sesión o señales de salud del sitio.

¿Cómo sé si la carga de la solicitud o los selectores están mal?

Comience verificando la respuesta protegida devuelta por el nodo HTTP Request.

  • Si la respuesta sigue bloqueada o incompleta, la forma de la solicitud probablemente es incorrecta.
  • Si la respuesta es correcta pero la extracción falla, los selectores o la lógica de análisis probablemente son incorrectos.

Depure el flujo de trabajo en ese orden: resolver -> enviar -> inspeccionar respuesta -> extraer.

Ver más

n8nMar 09, 2026

Cómo Resolver reCAPTCHA v2/v3 Usando CapSolver y n8n

Crea una API para resolver reCAPTCHA v2/v3 utilizando CapSolver y n8n. Aprende a automatizar la obtención de tokens, enviarlos a los sitios web y extraer datos protegidos sin necesidad de programar.

Aloísio Vítor
Aloísio Vítor
Apr 22, 2026

Mejor IA para resolver acertijos de imágenes: Mejores herramientas y estrategias para 2026

Descubre la mejor inteligencia artificial para resolver acertijos de imágenes. Aprende cómo el Motor de Visión de CapSolver y las APIs ImageToText automatizan desafíos visuales complejos con alta precisión.

Contenido

Aloísio Vítor
Aloísio Vítor
web scrapingApr 22, 2026

Arquitectura de raspado de web para extracción de datos escalable

Aprende una arquitectura de raspado web escalable en Rust con reqwest, scraper, raspado asíncrono, raspado con navegador sin cabeza, rotación de proxies y manejo de CAPTCHA conforme.

Aloísio Vítor
Aloísio Vítor
Apr 22, 2026

API de búsqueda vs. Cadena de suministro de conocimiento: Guía de infraestructura de datos de IA

Aprende cómo las herramientas de API de búsqueda, las cadenas de suministro de conocimiento, los flujos de trabajo de API SERP y las tuberías de datos de IA modelan la infraestructura de datos web moderna para la IA.

Aloísio Vítor
Aloísio Vítor
Blog
All