CAPSOLVER
Blog
Cómo resolver un Captcha en Browser4 con la integración de CapSolver

Cómo resolver Captcha en Browser4 con integración de CapSolver

Logo of CapSolver

Aloísio Vítor

Image Processing Expert

21-Jan-2026

Para la automatización web, Browser4 (de PulsarRPA ) ha surgido como un motor de navegador rápido y seguro para coroutines, diseñado para la extracción de datos impulsada por IA. Con capacidades que permiten 100k-200k visitas a páginas complejas por máquina por día, Browser4 está construido para escalar a gran escala. Sin embargo, al extraer datos de sitios web protegidos, los desafíos CAPTCHA se convierten en una barrera significativa.

CapSolver proporciona un complemento perfecto a las capacidades de automatización de Browser4, permitiendo a sus agentes navegar a través de páginas protegidas por CAPTCHA de manera fluida. Esta integración combina la automatización de navegadores de alta capacidad de Browser4 con soluciones líderes en la industria para resolver CAPTCHA.


¿Qué es Browser4?

Browser4 es un framework de automatización de navegadores de alto rendimiento construido en Kotlin. Está diseñado para aplicaciones de IA que requieren capacidades de agentes autónomos, alta capacidad de procesamiento y extracción de datos híbrida que combina LLM, algoritmos de aprendizaje automático y enfoques basados en selectores.

Características clave de Browser4

  • Alta capacidad de procesamiento: 100k-200k visitas a páginas complejas por máquina por día
  • Seguro para coroutines: Construido con coroutines de Kotlin para un procesamiento paralelo eficiente
  • Agentes impulsados por IA: Agentes de navegador autónomos capaces de razonar y ejecutar tareas de múltiples pasos
  • Extracción híbrida: Combina la inteligencia de LLM, algoritmos de aprendizaje automático y selectores CSS/XPath
  • Consultas X-SQL: Sintaxis de SQL extendida para la extracción de datos complejos
  • Funciones anti-bot: Rotación de perfiles, soporte de proxies y programación resiliente

Métodos de API principales

Método Descripción
session.open(url) Carga una página y devuelve un PageSnapshot
session.parse(page) Convierte el snapshot en un documento en memoria
driver.selectFirstTextOrNull(selector) Recupera texto del DOM en tiempo real
driver.evaluate(script) Ejecuta JavaScript en el navegador
session.extract(document, fieldMap) Mapea selectores CSS a campos estructurados

¿Qué es CapSolver?

CapSolver es un servicio líder de resolución de CAPTCHA que proporciona soluciones impulsadas por IA para evitar diversos desafíos de CAPTCHA. Con soporte para múltiples tipos de CAPTCHA y tiempos de respuesta rápidos, CapSolver se integra de manera fluida en flujos de trabajo automatizados.

Tipos de CAPTCHA compatibles


¿Por qué integrar CapSolver con Browser4?

Al construir automatización de Browser4 que interactúa con sitios web protegidos, ya sea para extracción de datos, monitoreo de precios o investigación de mercados, los desafíos CAPTCHA se convierten en una barrera significativa. Estas son las razones por las que la integración es importante:

  1. Extracción de alta capacidad sin interrupciones: Mantener 100k+ visitas diarias a páginas sin bloqueos de CAPTCHA
  2. Operaciones escalables: Manejar CAPTCHAS en ejecuciones paralelas de coroutines
  3. Flujo de trabajo sin interrupciones: Resolver CAPTCHAS como parte de su pipeline de extracción
  4. Costo efectivo: Pagar solo por CAPTCHAS resueltas con éxito
  5. Altas tasas de éxito: Precisión líder en la industria para todos los tipos de CAPTCHA compatibles

Instalación

Requisitos previos

Añadir dependencias

Maven (pom.xml):

xml Copy
<dependencies>
    <!-- Browser4/PulsarRPA -->
    <dependency>
        <groupId>ai.platon.pulsar</groupId>
        <artifactId>pulsar-boot</artifactId>
        <version>2.2.0</version>
    </dependency>

    <!-- Cliente HTTP para CapSolver -->
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.12.0</version>
    </dependency>

    <!-- Análisis JSON -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.10.1</version>
    </dependency>

    <!-- Coroutines de Kotlin -->
    <dependency>
        <groupId>org.jetbrains.kotlinx</groupId>
        <artifactId>kotlinx-coroutines-core</artifactId>
        <version>1.8.0</version>
    </dependency>
</dependencies>

Gradle (build.gradle.kts):

kotlin Copy
dependencies {
    implementation("ai.platon.pulsar:pulsar-boot:2.2.0")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("com.google.code.gson:gson:2.10.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
}

Configuración del entorno

Cree un archivo application.properties:

properties Copy
# Configuración de CapSolver
CAPSOLVER_API_KEY=your_capsolver_api_key

# Configuración de LLM (opcional, para extracción de IA)
OPENROUTER_API_KEY=your_openrouter_api_key

# Configuración de proxy (opcional)
PROXY_ROTATION_URL=your_proxy_url

Creando un servicio de CapSolver para Browser4

Aquí hay un servicio de Kotlin reutilizable que integra CapSolver con Browser4:

Servicio básico de CapSolver

kotlin Copy
import com.google.gson.Gson
import com.google.gson.JsonObject
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import kotlinx.coroutines.delay
import java.util.concurrent.TimeUnit

data class TaskResult(
    val gRecaptchaResponse: String? = null,
    val token: String? = null,
    val cookies: List<Map<String, String>>? = null,
    val userAgent: String? = null
)

class CapSolverService(private val apiKey: String) {
    private val client = OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build()

    private val gson = Gson()
    private val baseUrl = "https://api.capsolver.com"
    private val jsonMediaType = "application/json".toMediaType()

    private suspend fun createTask(taskData: Map<String, Any>): String {
        val payload = mapOf(
            "clientKey" to apiKey,
            "task" to taskData
        )

        val request = Request.Builder()
            .url("$baseUrl/createTask")
            .post(gson.toJson(payload).toRequestBody(jsonMediaType))
            .build()

        val response = client.newCall(request).execute()
        val result = gson.fromJson(response.body?.string(), JsonObject::class.java)

        if (result.get("errorId").asInt != 0) {
            throw Exception("Error de CapSolver: ${result.get("errorDescription").asString}")
        }

        return result.get("taskId").asString
    }

    private suspend fun getTaskResult(taskId: String, maxAttempts: Int = 60): TaskResult {
        val payload = mapOf(
            "clientKey" to apiKey,
            "taskId" to taskId
        )

        repeat(maxAttempts) {
            delay(2000)

            val request = Request.Builder()
                .url("$baseUrl/getTaskResult")
                .post(gson.toJson(payload).toRequestBody(jsonMediaType))
                .build()

            val response = client.newCall(request).execute()
            val result = gson.fromJson(response.body?.string(), JsonObject::class.java)

            when (result.get("status")?.asString) {
                "ready" -> {
                    val solution = result.getAsJsonObject("solution")
                    return TaskResult(
                        gRecaptchaResponse = solution.get("gRecaptchaResponse")?.asString,
                        token = solution.get("token")?.asString,
                        userAgent = solution.get("userAgent")?.asString
                    )
                }
                "failed" -> throw Exception("Tarea fallida: ${result.get("errorDescription")?.asString}")
            }
        }

        throw Exception("Tiempo agotado esperando la solución de CAPTCHA")
    }

    suspend fun solveReCaptchaV2(websiteUrl: String, websiteKey: String): String {
        val taskId = createTask(mapOf(
            "type" to "ReCaptchaV2TaskProxyLess",
            "websiteURL" to websiteUrl,
            "websiteKey" to websiteKey
        ))

        val result = getTaskResult(taskId)
        return result.gRecaptchaResponse ?: throw Exception("No se encontró gRecaptchaResponse en la solución")
    }

    suspend fun solveReCaptchaV3(
        websiteUrl: String,
        websiteKey: String,
        pageAction: String = "submit"
    ): String {
        val taskId = createTask(mapOf(
            "type" to "ReCaptchaV3TaskProxyLess",
            "websiteURL" to websiteUrl,
            "websiteKey" to websiteKey,
            "pageAction" to pageAction
        ))

        val result = getTaskResult(taskId)
        return result.gRecaptchaResponse ?: throw Exception("No se encontró gRecaptchaResponse en la solución")
    }

    suspend fun solveTurnstile(
        websiteUrl: String,
        websiteKey: String,
        action: String? = null,
        cdata: String? = null
    ): String {
        val taskData = mutableMapOf(
            "type" to "AntiTurnstileTaskProxyLess",
            "websiteURL" to websiteUrl,
            "websiteKey" to websiteKey
        )

        // Añadir metadatos opcionales
        if (action != null || cdata != null) {
            val metadata = mutableMapOf<String, String>()
            action?.let { metadata["action"] = it }
            cdata?.let { metadata["cdata"] = it }
            taskData["metadata"] = metadata
        }

        val taskId = createTask(taskData)
        val result = getTaskResult(taskId)
        return result.token ?: throw Exception("No se encontró token en la solución")
    }

    suspend fun checkBalance(): Double {
        val payload = mapOf("clientKey" to apiKey)

        val request = Request.Builder()
            .url("$baseUrl/getBalance")
            .post(gson.toJson(payload).toRequestBody(jsonMediaType))
            .build()

        val response = client.newCall(request).execute()
        val result = gson.fromJson(response.body?.string(), JsonObject::class.java)

        return result.get("balance")?.asDouble ?: 0.0
    }
}

Resolviendo diferentes tipos de CAPTCHA

reCAPTCHA v2 con Browser4

kotlin Copy
import ai.platon.pulsar.context.PulsarContexts
import ai.platon.pulsar.skeleton.session.PulsarSession
import kotlinx.coroutines.runBlocking

class ReCaptchaV2Extractor(
    private val capSolver: CapSolverService
) {
    suspend fun extractWithCaptcha(targetUrl: String, siteKey: String): Map<String, Any?> {
        println("Resolviendo reCAPTCHA v2...")

        // Resolver la CAPTCHA primero
        val token = capSolver.solveReCaptchaV2(targetUrl, siteKey)
        println("CAPTCHA resuelta, longitud del token: ${token.length}")

        // Crear sesión y abrir la página
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        // Inyectar el token en el campo de texto oculto usando la propiedad value (seguro)
        driver?.evaluate("""
            (function() {
                var el = document.querySelector('#g-recaptcha-response');
                if (el) el.value = arguments[0];
            })('$token');
        """)

        // Enviar el formulario
        driver?.evaluate("document.querySelector('form').submit();")

        // Esperar la navegación
        Thread.sleep(3000)

        // Extraer datos de la página resultante
        val document = session.parse(page)

        mapOf(
            "título" to document.selectFirstTextOrNull("h1"),
            "contenido" to document.selectFirstTextOrNull(".contenido"),
            "éxito" to (document.body().text().contains("éxito", ignoreCase = true))
        )
    }
}

fun main() = runBlocking {
    val apiKey = System.getenv("CAPSOLVER_API_KEY") ?: "su_api_key"
    val capSolver = CapSolverService(apiKey)

    val extractor = ReCaptchaV2Extractor(capSolver)

    val result = extractor.extractWithCaptcha(
        targetUrl = "https://ejemplo.com/página-protegida",
        siteKey = "6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC"
    )

    println("Resultado de la extracción: $result")
}

reCAPTCHA v3 con Browser4

kotlin Copy
class ReCaptchaV3Extractor(
    private val capSolver: CapSolverService
) {
    suspend fun extractWithCaptchaV3(
        targetUrl: String,
        siteKey: String,
        action: String = "submit"
    ): Map<String, Any?> {
        println("Resolviendo reCAPTCHA v3 con acción: $action")

        // Resolver reCAPTCHA v3 con acción de página personalizada
        val token = capSolver.solveReCaptchaV3(
            websiteUrl = targetUrl,
            websiteKey = siteKey,
            pageAction = action
        )

        println("Token obtenido con éxito")

        // Crear sesión y abrir la página
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        // Inyectar token en campo oculto (usando asignación segura de valor)
        driver?.evaluate("""
            (function(tokenValue) {
                var input = document.querySelector('input[name="g-recaptcha-response"]');
                if (input) {
                    input.value = tokenValue;
                } else {
                    var hidden = document.createElement('input');
                    hidden.type = 'hidden';
                    hidden.name = 'g-recaptcha-response';
                    hidden.value = tokenValue;
                    var form = document.querySelector('form');
                    if (form) form.appendChild(hidden);
                }
            })('$token');
        """)

        // Hacer clic en el botón de envío
        driver?.evaluate("document.querySelector('#submit-btn').click();")

        Thread.sleep(3000)

        val document = session.parse(page)

        mapOf(
            "resultado" to document.selectFirstTextOrNull(".datos-resultados"),
            "estado" to "éxito"
        )
    }
}

Cloudflare Turnstile con Browser4

kotlin Copy
class TurnstileExtractor(
    private val capSolver: CapSolverService
) {
    suspend fun extractWithTurnstile(targetUrl: String, siteKey: String): Map<String, Any?> {
        println("Resolviendo Cloudflare Turnstile...")

        // Resolver con metadatos opcionales (acción y cdata)

val token = capSolver.solveTurnstile(
targetUrl,
siteKey,
action = "login", // opcional
cdata = "0000-1111-2222-3333-ejemplo" // opcional
)
println("¡Turnstile resuelto!")

Copy
    val session = PulsarContexts.createSession()
    val page = session.open(targetUrl)
    val driver = session.getOrCreateBoundDriver()

    // Inyectar token de Turnstile (usando asignación segura de valores)
    driver?.evaluate("""
        (function(tokenValue) {
            var input = document.querySelector('input[name="cf-turnstile-response"]');
            if (input) input.value = tokenValue;
        })('$token');
    """)

    // Enviar formulario
    driver?.evaluate("document.querySelector('form').submit();")

    Thread.sleep(3000)

    val document = session.parse(page)

    mapOf(
        "title" to document.selectFirstTextOrNull("title"),
        "content" to document.selectFirstTextOrNull("body")?.take(500)
    )
}

}

Copy
---

## Integración con Browser4 X-SQL

Browser4's X-SQL proporciona capacidades poderosas de extracción. Así es como se combina con la resolución de CAPTCHA:

```kotlin
class XSqlCaptchaExtractor(
    private val capSolver: CapSolverService
) {
    suspend fun extractProductsWithCaptcha(
        targetUrl: String,
        siteKey: String
    ): List<Map<String, Any?>> {
        // Resolver CAPTCHA previamente
        val token = capSolver.solveReCaptchaV2(targetUrl, siteKey)

        // Crear sesión y establecer sesión autenticada
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        driver?.evaluate("""
            (function(tokenValue) {
                var el = document.querySelector('#g-recaptcha-response');
                if (el) el.value = tokenValue;
                document.querySelector('form').submit();
            })('$token');
        """)

        Thread.sleep(3000)

        // Ahora analizar la página y extraer datos de productos
        val document = session.parse(page)

        // Extraer datos de productos usando métodos integrados de sesión
        val products = mutableListOf<Map<String, Any?>>()
        val productElements = document.select(".product-item")

        for ((index, element) in productElements.withIndex()) {
            if (index >= 50) break // LÍMITE 50
            products.add(mapOf(
                "name" to element.selectFirstTextOrNull(".product-name"),
                "price" to element.selectFirstTextOrNull(".price")?.let {
                    """(\d+\.?\d*)""".toRegex().find(it)?.groupValues?.get(1)?.toDoubleOrNull() ?: 0.0
                },
                "rating" to element.selectFirstTextOrNull(".rating")
            ))
        }

        return products.map { row ->
            mapOf(
                "name" to row["name"],
                "price" to row["price"],
                "rating" to row["rating"],
                "image_url" to row["image_url"]
            )
        }
    }
}

Patrón de Autenticación Previa

Para sitios que requieren CAPTCHA antes de acceder al contenido, utilice un flujo de trabajo de autenticación previa:

kotlin Copy
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl

class PreAuthenticator(
    private val capSolver: CapSolverService
) {
    data class AuthSession(
        val cookies: Map<String, String>,
        val userAgent: String?
    )

    suspend fun authenticateWithCaptcha(
        loginUrl: String,
        siteKey: String
    ): AuthSession {
        // Resolver CAPTCHA
        val captchaToken = capSolver.solveReCaptchaV2(loginUrl, siteKey)

        // Enviar CAPTCHA para obtener cookies de sesión
        val client = OkHttpClient.Builder()
            .cookieJar(object : CookieJar {
                private val cookies = mutableListOf<Cookie>()

                override fun saveFromResponse(url: HttpUrl, cookieList: List<Cookie>) {
                    cookies.addAll(cookieList)
                }

                override fun loadForRequest(url: HttpUrl): List<Cookie> = cookies
            })
            .build()

        val formBody = okhttp3.FormBody.Builder()
            .add("g-recaptcha-response", captchaToken)
            .build()

        val request = Request.Builder()
            .url(loginUrl)
            .post(formBody)
            .build()

        val response = client.newCall(request).execute()

        // Extraer cookies de la respuesta
        val responseCookies = response.headers("Set-Cookie")
            .associate { cookie ->
                val parts = cookie.split(";")[0].split("=", limit = 2)
                parts[0] to (parts.getOrNull(1) ?: "")
            }

        return AuthSession(
            cookies = responseCookies,
            userAgent = response.request.header("User-Agent")
        )
    }
}

class AuthenticatedExtractor(
    private val preAuth: PreAuthenticator,
    private val capSolver: CapSolverService
) {
    suspend fun extractWithAuth(
        loginUrl: String,
        targetUrl: String,
        siteKey: String
    ): Map<String, Any?> {
        // Autenticar previamente
        val authSession = preAuth.authenticateWithCaptcha(loginUrl, siteKey)
        println("Sesión establecida con ${authSession.cookies.size} cookies")

        // Crear sesión de Browser4
        val session = PulsarContexts.createSession()

        // Configurar sesión con cookies
        val cookieScript = authSession.cookies.entries.joinToString(";") { (k, v) ->
            "$k=$v"
        }

        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        // Establecer cookies
        driver?.evaluate("document.cookie = '$cookieScript';")

        // Recargar con sesión autenticada
        driver?.evaluate("location.reload();")
        Thread.sleep(2000)

        // Extraer datos
        val document = session.parse(page)

        return mapOf(
            "authenticated" to true,
            "content" to document.selectFirstTextOrNull(".protected-content"),
            "userData" to document.selectFirstTextOrNull(".user-profile")
        )
    }
}

Servicio de OpenRouter para Extracción con IA

Las capacidades de inteligencia artificial de Browser4 se pueden mejorar con OpenRouter, una puerta de enlace unificada para acceder a diversos modelos de lenguaje. Esto permite una extracción inteligente de contenido que se adapta a diferentes estructuras de página.

Servicio de OpenRouter

kotlin Copy
import com.google.gson.Gson
import com.google.gson.JsonObject
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.util.concurrent.TimeUnit

data class ChatMessage(val role: String, val content: String)
data class ChatCompletion(val content: String, val model: String, val usage: TokenUsage)
data class TokenUsage(val promptTokens: Int, val completionTokens: Int, val totalTokens: Int)

class OpenRouterService(private val apiKey: String) {
    private val client = OkHttpClient.Builder()
        .connectTimeout(60, TimeUnit.SECONDS)
        .readTimeout(60, TimeUnit.SECONDS)
        .build()

    private val gson = Gson()
    private val baseUrl = "https://openrouter.ai/api/v1"
    private val jsonMediaType = "application/json".toMediaType()

    fun chat(
        messages: List<ChatMessage>,
        model: String = "openai/gpt-4o-mini"
    ): ChatCompletion {
        val payload = mapOf(
            "model" to model,
            "messages" to messages.map { mapOf("role" to it.role, "content" to it.content) }
        )

        val request = Request.Builder()
            .url("$baseUrl/chat/completions")
            .header("Authorization", "Bearer $apiKey")
            .post(gson.toJson(payload).toRequestBody(jsonMediaType))
            .build()

        val response = client.newCall(request).execute()
        val result = gson.fromJson(response.body?.string(), JsonObject::class.java)

        val choice = result.getAsJsonArray("choices")?.get(0)?.asJsonObject
        val content = choice?.getAsJsonObject("message")?.get("content")?.asString ?: ""

        val usage = result.getAsJsonObject("usage")

        return ChatCompletion(
            content = content,
            model = result.get("model")?.asString ?: model,
            usage = TokenUsage(
                promptTokens = usage?.get("prompt_tokens")?.asInt ?: 0,
                completionTokens = usage?.get("completion_tokens")?.asInt ?: 0,
                totalTokens = usage?.get("total_tokens")?.asInt ?: 0
            )
        )
    }

    fun extractStructuredData(html: String, schema: String): String {
        val prompt = """
            Extraiga los siguientes datos del contenido HTML.
            Devuelva SOLO JSON válido que coincida con este esquema: $schema

            HTML:
            ${html.take(4000)}
        """.trimIndent()

        return chat(listOf(ChatMessage("user", prompt))).content
    }

    fun listModels(): List<String> {
        val request = Request.Builder()
            .url("$baseUrl/models")
            .header("Authorization", "Bearer $apiKey")
            .build()

        val response = client.newCall(request).execute()
        val result = gson.fromJson(response.body?.string(), JsonObject::class.java)

        return result.getAsJsonArray("data")?.mapNotNull {
            it.asJsonObject.get("id")?.asString
        } ?: emptyList()
    }
}

Extracción con IA y Resolución de CAPTCHA

Combine la resolución de CAPTCHA con la extracción inteligente de datos:

kotlin Copy
class SmartExtractor(
    private val capSolver: CapSolverService,
    private val openRouter: OpenRouterService
) {
    suspend fun extractWithAI(
        targetUrl: String,
        siteKey: String?,
        extractionPrompt: String
    ): Map<String, Any?> {
        // Paso 1: Resolver CAPTCHA si es necesario
        val captchaToken = siteKey?.let {
            println("Resolviendo CAPTCHA...")
            capSolver.solveReCaptchaV2(targetUrl, it)
        }

        // Paso 2: Crear sesión y abrir página
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        captchaToken?.let { token ->
            driver?.evaluate("""
                (function(tokenValue) {
                    var el = document.querySelector('#g-recaptcha-response');
                    if (el) el.value = tokenValue;
                    var form = document.querySelector('form');
                    if (form) form.submit();
                })('$token');
            """)
            Thread.sleep(3000)
        }

        // Paso 3: Extraer contenido de la página
        val document = session.parse(page)
        val pageContent = document.body().text().take(8000)

        // Paso 4: Usar IA para extraer datos estructurados
        val llmResponse = openRouter.chat(listOf(
            ChatMessage("system", "Eres un asistente de extracción de datos. Extraiga datos estructurados de páginas web."),
            ChatMessage("user", """
                $extractionPrompt

                Contenido de la página:
                $pageContent
            """.trimIndent())
        ))

        println("LLM usó ${llmResponse.usage.totalTokens} tokens")

        return mapOf(
            "url" to targetUrl,
            "captchaSolved" to (captchaToken != null),
            "extractedData" to llmResponse.content,
            "tokensUsed" to llmResponse.usage.totalTokens
        )
    }
}

// Uso
fun main() = runBlocking {
    val capSolver = CapSolverService(System.getenv("CAPSOLVER_API_KEY")!!)
    val openRouter = OpenRouterService(System.getenv("OPENROUTER_API_KEY")!!)

    val extractor = SmartExtractor(capSolver, openRouter)

    val result = extractor.extractWithAI(
        targetUrl = "https://example.com/products",
        siteKey = "6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC",
        extractionPrompt = """
            Extraiga todos los productos con:
            - nombre
            - precio (como número)
            - disponibilidad (en_stock/fuera_de_stock)
            - calificación (1-5)
            Devuélvalos como matriz JSON.
        """.trimIndent()
    )

    println("Resultado de extracción: ${result["extractedData"]}")
}

Generación de Selectores Adaptativos

Utilice LLM para generar selectores CSS para estructuras de página desconocidas:

kotlin Copy
class AdaptiveExtractor(
    private val capSolver: CapSolverService,
    private val openRouter: OpenRouterService
) {
    suspend fun extractWithAdaptiveSelectors(
        targetUrl: String,
        siteKey: String?,
        dataFields: List<String>
    ): Map<String, Any?> {
        // Resolver CAPTCHA primero
        val token = siteKey?.let { capSolver.solveReCaptchaV2(targetUrl, it) }

        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        token?.let { t ->
            driver?.evaluate("""
                (function(tokenValue) {
                    var el = document.querySelector('#g-recaptcha-response');
                    if (el) el.value = tokenValue;
                })('$t');
            """)
        }

        // Obtener estructura HTML de la página
        val htmlSample = driver?.evaluate("document.body.innerHTML")?.toString()?.take(5000) ?: ""

        // Pedir al LLM que genere selectores
        val selectorPrompt = """
            Analice este HTML y proporcione selectores CSS para estos campos: ${dataFields.joinToString(", ")}

            Muestra de HTML:
            $htmlSample

            Devuelva JSON como: {"fieldName": "css-selector", ...}
        """.trimIndent()

        val selectorsJson = openRouter.chat(listOf(ChatMessage("user", selectorPrompt))).content
        val selectors = Gson().fromJson(selectorsJson, Map::class.java) as Map<String, String>

        // Extraer usando selectores generados
        val document = session.parse(page)
        val extractedData = selectors.mapValues { (_, selector) ->
            document.selectFirstTextOrNull(selector)
        }

        return mapOf(
            "url" to targetUrl,
            "selectors" to selectors,
            "data" to extractedData
        )
    }
}

Extracción Paralela con Corrutinas

El diseño seguro para corrutinas de Browser4 permite un manejo eficiente de CAPTCHA en paralelo:

kotlin Copy
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel

data class ExtractionJob(
    val url: String,
    val siteKey: String?
)

data class ExtractionResult(
    val url: String,
    val data: Map<String, Any?>?,
    val captchaSolved: Boolean,
    val error: String?,
    val duration: Long
)

class ParallelExtractor(
    private val capSolver: CapSolverService,
    private val concurrency: Int = 5
) {
    suspend fun extractAll(jobs: List<ExtractionJob>): List<ExtractionResult> = coroutineScope {
        val channel = Channel<ExtractionJob>(Channel.UNLIMITED)
val results = mutableListOf<ExtractionResult>()

        // Enviar todos los trabajos al canal
        jobs.forEach { channel.send(it) }
        channel.close()

        // Procesar con concurrencia limitada
        val workers = (1..concurrency).map { workerId ->
            async {
                val workerResults = mutableListOf<ExtractionResult>()
                // Cada trabajador crea su propia sesión para seguridad de subprocesos
                val workerSession = PulsarContexts.createSession()

                for (job in channel) {
                    val startTime = System.currentTimeMillis()
                    var captchaSolved = false

                    try {
                        // Resolver CAPTCHA si se proporciona la clave del sitio
                        val token = job.siteKey?.let {
                            captchaSolved = true
                            capSolver.solveReCaptchaV2(job.url, it)
                        }

                        // Extraer datos
                        val page = workerSession.open(job.url)

                        token?.let { t ->
                            val driver = workerSession.getOrCreateBoundDriver()
                            driver?.evaluate("""
                                (function(tokenValue) {
                                    var el = document.querySelector('#g-recaptcha-response');
                                    if (el) el.value = tokenValue;
                                })('$t');
                            """)
                        }

                        val document = workerSession.parse(page)

                        workerResults.add(ExtractionResult(
                            url = job.url,
                            data = mapOf(
                                "title" to document.selectFirstTextOrNull("title"),
                                "h1" to document.selectFirstTextOrNull("h1")
                            ),
                            captchaSolved = captchaSolved,
                            error = null,
                            duration = System.currentTimeMillis() - startTime
                        ))
                    } catch (e: Exception) {
                        workerResults.add(ExtractionResult(
                            url = job.url,
                            data = null,
                            captchaSolved = captchaSolved,
                            error = e.message,
                            duration = System.currentTimeMillis() - startTime
                        ))
                    }
                }

                workerResults
            }
        }

        workers.awaitAll().flatten()
    }
}

// Uso
fun main() = runBlocking {
    val capSolver = CapSolverService(System.getenv("CAPSOLVER_API_KEY")!!)

    val extractor = ParallelExtractor(capSolver, concurrency = 5)

    val jobs = listOf(
        ExtractionJob("https://site1.com/data", "6Lc..."),
        ExtractionJob("https://site2.com/data", null),
        ExtractionJob("https://site3.com/data", "6Lc..."),
    )

    val results = extractor.extractAll(jobs)

    val solved = results.count { it.captchaSolved }
    println("Completado ${results.size} extracciones, resueltos $solved CAPTCHAs")

    results.forEach { r ->
        println("${r.url}: ${r.duration}ms - ${r.error ?: "éxito"}")
    }
}

Buenas prácticas

1. Manejo de errores con reintentos

kotlin Copy
suspend fun <T> withRetry(
    maxRetries: Int = 3,
    initialDelay: Long = 1000,
    block: suspend () -> T
): T {
    var lastException: Exception? = null

    repeat(maxRetries) { attempt ->
        try {
            return block()
        } catch (e: Exception) {
            lastException = e
            println("Intento ${attempt + 1} fallido: ${e.message}")
            delay(initialDelay * (attempt + 1))
        }
    }

    throw lastException ?: Exception("Se excedió el número máximo de reintentos")
}

// Uso
val token = withRetry(maxRetries = 3) {
    capSolver.solveReCaptchaV2(url, siteKey)
}

2. Gestión de balance

kotlin Copy
suspend fun ensureSufficientBalance(
    capSolver: CapSolverService,
    minBalance: Double = 1.0
) {
    val balance = capSolver.checkBalance()

    if (balance < minBalance) {
        throw Exception("Saldo insuficiente de CapSolver: $${"%.2f".format(balance)}. Por favor recargue.")
    }

    println("Saldo de CapSolver: $${"%.2f".format(balance)}")
}

3. Almacenamiento en caché de tokens

kotlin Copy
class TokenCache(private val ttlMs: Long = 90_000) {
    private data class CachedToken(val token: String, val timestamp: Long)

    private val cache = mutableMapOf<String, CachedToken>()

    private fun getKey(domain: String, siteKey: String) = "$domain:$siteKey"

    fun get(domain: String, siteKey: String): String? {
        val key = getKey(domain, siteKey)
        val cached = cache[key] ?: return null

        if (System.currentTimeMillis() - cached.timestamp > ttlMs) {
            cache.remove(key)
            return null
        }

        return cached.token
    }

    fun set(domain: String, siteKey: String, token: String) {
        val key = getKey(domain, siteKey)
        cache[key] = CachedToken(token, System.currentTimeMillis())
    }
}

// Uso con caché
class CachedCapSolver(
    private val capSolver: CapSolverService,
    private val cache: TokenCache = TokenCache()
) {
    suspend fun solveReCaptchaV2Cached(websiteUrl: String, websiteKey: String): String {
        val domain = java.net.URL(websiteUrl).host

        cache.get(domain, websiteKey)?.let {
            println("Usar token en caché")
            return it
        }

        val token = capSolver.solveReCaptchaV2(websiteUrl, websiteKey)
        cache.set(domain, websiteKey, token)

        return token
    }
}

Opciones de configuración

Configuración Descripción Predeterminado
CAPSOLVER_API_KEY Su clave de API de CapSolver -
OPENROUTER_API_KEY Clave de API de OpenRouter para funciones de LLM -
PROXY_ROTATION_URL URL del servicio de rotación de proxies -
Browser4 usa application.properties para configuración adicional

Conclusión

La integración de CapSolver con Browser4 crea una combinación poderosa para la extracción de datos web a gran escala. La arquitectura segura para corutinas y las capacidades de rendimiento extremo de Browser4, combinadas con la resolución confiable de CAPTCHAs de CapSolver, permiten la extracción a escala.

Patrones clave de integración:

  1. Inyección de token directa: Inyectar tokens resueltos mediante la evaluación de JavaScript
  2. Autenticación previa: Resolver CAPTCHAs para establecer sesiones antes de la extracción
  3. Procesamiento paralelo: Aprovechar corutinas para manejar CAPTCHAs concurrentes
  4. Integración con X-SQL: Combinar resolución de CAPTCHAs con el lenguaje de consulta potente de Browser4

Ya sea que esté construyendo sistemas de monitoreo de precios, flujos de investigación de mercado o plataformas de agregación de datos, la combinación Browser4 + CapSolver proporciona la confiabilidad y escalabilidad necesarias para entornos de producción.


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


Preguntas frecuentes

¿Qué es Browser4?

Browser4 es un marco de automatización de navegadores de alto rendimiento y seguro para corutinas de PulsarRPA. Está escrito en Kotlin y está diseñado para la extracción de datos impulsada por IA, admitiendo 100.000 a 200.000 visitas a páginas complejas por máquina por día.

¿Cómo se integra CapSolver con Browser4?

CapSolver se integra con Browser4 a través de una clase de servicio que resuelve CAPTCHAs mediante la API de CapSolver. Los tokens resueltos luego se inyectan en las páginas usando las capacidades de evaluación de JavaScript de Browser4 (driver.evaluate()).

¿Qué tipos de CAPTCHAs puede resolver CapSolver?

CapSolver admite reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, Cloudflare Challenge (5 segundos), AWS WAF, GeeTest v3/v4 y muchos más.

¿Cuánto cuesta CapSolver?

CapSolver ofrece precios competitivos según el tipo y volumen de CAPTCHAs resueltos. Visite capsolver.com para conocer los precios actuales. Use el código BROWSER4 para obtener un 6% de bonificación.

¿Qué lenguaje de programación utiliza Browser4?

Browser4 está construido en Kotlin y funciona en la JVM (Java 17+). También se puede utilizar desde aplicaciones Java.

¿Puede Browser4 manejar la resolución de CAPTCHAs en paralelo?

Sí. El diseño seguro para corutinas de Browser4 permite un procesamiento eficiente en paralelo. Combinado con la API de CapSolver, puede resolver múltiples CAPTCHAs concurrentemente en diferentes trabajos de extracción.

¿Cómo encuentro la clave del CAPTCHA?

La clave del sitio normalmente se encuentra en la fuente HTML de la página:

  • reCAPTCHA: atributo data-sitekey en el elemento .g-recaptcha
  • Turnstile: atributo data-sitekey en el elemento .cf-turnstile
  • O revise las solicitudes de red para encontrar la clave en llamadas a la API

Aviso de Cumplimiento: La información proporcionada en este blog es solo para fines informativos. CapSolver se compromete a cumplir con todas las leyes y regulaciones aplicables. El uso de la red de CapSolver para actividades ilegales, fraudulentas o abusivas está estrictamente prohibido y será investigado. Nuestras soluciones para la resolución de captcha mejoran la experiencia del usuario mientras garantizan un 100% de cumplimiento al ayudar a resolver las dificultades de captcha durante el rastreo de datos públicos. Fomentamos el uso responsable de nuestros servicios. Para obtener más información, visite nuestros Términos de Servicio y Política de Privacidad.

Máse

Relevance AI con CapSolver
Cómo resolver reCAPTCHA v2 en Relevance AI con integración de CapSolver

Construye una herramienta de Relevance AI para resolver reCAPTCHA v2 utilizando CapSolver. Automatiza los envíos de formularios a través de API sin automatización de navegadores.

web scraping
Logo of CapSolver

Aloísio Vítor

03-Feb-2026

Herramientas de Scraping de Datos Instantáneas: Formas Rápidas para Extraer Datos de la Web Sin Código
Herramientas de Scraping de Datos Instantáneo: Formas Rápidas para Extraer Datos de la Web Sin Código

Descubre las mejores herramientas de scraping para 2026. Aprende formas rápidas de extraer datos de la web sin código usando las mejores extensiones y APIs para la extracción automatizada.

web scraping
Logo of CapSolver

Rajinder Singh

28-Jan-2026

Raspado de Web Artículos de Noticias
Raspado Web de Artículos de Noticias con Python (Guía para 2026)

Domina el scraping web de artículos de noticias con Python en 2026. Aprende a resolver reCAPTCHA v2/v3 con CapSolver y construye pipelines de datos escalables.

web scraping
Logo of CapSolver

Adélia Cruz

28-Jan-2026

Top 10 de Escrapers sin Código para Usar en 2026
Top 10 Scrapers sin código para usar en 2026

Una lista curada de las mejores herramientas de scraping web sin código para usar en 2026. Comparar scrapers con inteligencia artificial, plataformas visuales de punto y clic, precios, ventajas y desventajas, y casos de uso del mundo real.

web scraping
Logo of CapSolver

Adélia Cruz

27-Jan-2026

Baneos de IP en 2026: Cómo funcionan y Formas prácticas de evadirlos
Bloqueos de IP en 2026: Cómo funcionan y Formas prácticas de evadirlos

Aprende cómo evitar el bloqueo de IP en 2026 con nuestro guía completa. Descubre técnicas modernas de bloqueo de IP y soluciones prácticas como proxies residenciales y resolutores de CAPTCHA.

web scraping
Logo of CapSolver

Rajinder Singh

26-Jan-2026

Maxun con integración de CapSolver
Cómo resolver Captcha en Maxun con integración de CapSolver

Una guía práctica para integrar CapSolver con Maxun para el scraping de web en el mundo real. Aprende cómo manejar reCAPTCHA, Cloudflare Turnstile y sitios protegidos por CAPTCHA utilizando flujos de trabajo de pre-autenticación y robot.

web scraping
Logo of CapSolver

Adélia Cruz

21-Jan-2026