CAPSOLVER
Blog
Cara Menyelesaikan Captcha di Browser4 dengan Integrasi CapSolver

Cara menyelesaikan Captcha di Browser4 dengan integrasi CapSolver

Logo of CapSolver

Anh Tuan

Data Science Expert

21-Jan-2026

Untuk otomatisasi web, Browser4 (dari PulsarRPA) telah muncul sebagai mesin browser yang cepat, aman korutin, yang dirancang untuk ekstraksi data berkekuatan AI. Dengan kemampuan yang mendukung 100k-200k kunjungan halaman kompleks per mesin per hari, Browser4 dirancang untuk skala yang serius. Namun, ketika mengekstrak data dari situs web yang dilindungi, tantangan CAPTCHA menjadi penghalang yang signifikan.

CapSolver memberikan pelengkap yang sempurna untuk kemampuan otomatisasi Browser4, memungkinkan agen Anda untuk menavigasi halaman yang dilindungi CAPTCHA secara mulus. Integrasi ini menggabungkan otomatisasi browser berkecepatan tinggi Browser4 dengan solusi CAPTCHA yang unggul di industri.


Apa itu Browser4?

Browser4 adalah kerangka kerja otomatisasi browser berkinerja tinggi yang dibangun dalam Kotlin. Dirancang untuk aplikasi AI yang memerlukan kemampuan agen mandiri, throughput ekstrem, dan ekstraksi data hibrid yang menggabungkan LLM, algoritma machine learning, dan pendekatan berbasis selector.

Fitur Utama Browser4

  • Throughput Ekstrem: 100k-200k kunjungan halaman kompleks per mesin per hari
  • Aman Korutin: Dibangun dengan korutin Kotlin untuk pemrosesan paralel yang efisien
  • Agen Berkekuatan AI: Agen browser mandiri yang mampu berpikir dan menjalankan tugas multi-langkah
  • Ekstraksi Hibrid: Menggabungkan kecerdasan LLM, algoritma ML, dan selector CSS/XPath
  • Pertanyaan X-SQL: Sintaks SQL yang diperluas untuk ekstraksi data kompleks
  • Fitur Anti-Bot: Rotasi profil, dukungan proxy, dan penjadwalan yang tangguh

Metode API Inti

Metode Deskripsi
session.open(url) Memuat halaman dan mengembalikan PageSnapshot
session.parse(page) Mengonversi snapshot menjadi dokumen di memori
driver.selectFirstTextOrNull(selector) Mengambil teks dari DOM yang sedang berjalan
driver.evaluate(script) Menjalankan JavaScript di browser
session.extract(document, fieldMap) Memetakan selector CSS ke bidang yang terstruktur

Apa itu CapSolver?

CapSolver adalah layanan penyelesaian CAPTCHA yang terkemuka yang menyediakan solusi berkekuatan AI untuk melewati berbagai tantangan CAPTCHA. Dengan dukungan untuk berbagai jenis CAPTCHA dan respons yang cepat, CapSolver terintegrasi secara mulus ke dalam alur kerja otomatis.

Jenis CAPTCHA yang Didukung


Mengapa Mengintegrasikan CapSolver dengan Browser4?

Ketika membangun otomatisasi Browser4 yang berinteraksi dengan situs web yang dilindungi—baik untuk ekstraksi data, pemantauan harga, atau penelitian pasar—tantangan CAPTCHA menjadi penghalang yang signifikan. Berikut adalah alasan mengapa integrasi ini penting:

  1. Ekstraksi Throughput Tanpa Gangguan: Pertahankan 100k+ kunjungan halaman per hari tanpa blokir CAPTCHA
  2. Operasi yang Dapat Diperluas: Menangani CAPTCHA di seluruh eksekusi korutin paralel
  3. Alur Kerja yang Lancar: Menyelesaikan CAPTCHA sebagai bagian dari pipeline ekstraksi Anda
  4. Efisien Biaya: Bayar hanya untuk CAPTCHA yang berhasil diselesaikan
  5. Tingkat Keberhasilan Tinggi: Akurasi terkemuka di industri untuk semua jenis CAPTCHA yang didukung

Instalasi

Prasyarat

  • Java 17 atau lebih tinggi
  • Maven 3.6+ atau Gradle
  • Kunci API CapSolver

Menambahkan Dependency

Maven (pom.xml):

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

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

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

    <!-- Korutin 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")
}

Pengaturan Lingkungan

Buat file application.properties:

properties Copy
# Konfigurasi CapSolver
CAPSOLVER_API_KEY=kunci_api_capsolver_anda

# Konfigurasi LLM (opsional, untuk ekstraksi AI)
OPENROUTER_API_KEY=kunci_api_openrouter_anda

# Konfigurasi Proxy (opsional)
PROXY_ROTATION_URL=url_proxy_anda

Membuat Layanan CapSolver untuk Browser4

Berikut adalah layanan Kotlin yang dapat digunakan kembali yang mengintegrasikan CapSolver dengan Browser4:

Layanan Dasar 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("Kesalahan 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("Tugas gagal: ${result.get("errorDescription")?.asString}")
            }
        }

        throw Exception("Waktu tunggu solusi CAPTCHA habis")
    }

    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("Tidak ada gRecaptchaResponse dalam solusi")
    }

    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("Tidak ada gRecaptchaResponse dalam solusi")
    }

    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
        )

        // Tambahkan metadata opsional
        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("Tidak ada token dalam solusi")
    }

    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
    }
}

Menyelesaikan Berbagai Jenis CAPTCHA

reCAPTCHA v2 dengan 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("Menyelesaikan reCAPTCHA v2...")

        // Selesaikan CAPTCHA terlebih dahulu
        val token = capSolver.solveReCaptchaV2(targetUrl, siteKey)
        println("CAPTCHA diselesaikan, panjang token: ${token.length}")

        // Buat sesi dan buka halaman
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        // Sisipkan token ke textarea tersembunyi menggunakan properti value (aman)
        driver?.evaluate("""
            (function() {
                var el = document.querySelector('#g-recaptcha-response');
                if (el) el.value = arguments[0];
            })('$token');
        """)

        // Kirim formulir
        driver?.evaluate("document.querySelector('form').submit();")

        // Tunggu navigasi
        Thread.sleep(3000)

        // Ekstrak data dari halaman hasil
        val document = session.parse(page)

        mapOf(
            "title" to document.selectFirstTextOrNull("h1"),
            "content" to document.selectFirstTextOrNull(".content"),
            "success" to (document.body().text().contains("success", ignoreCase = true))
        )
    }
}

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

    val extractor = ReCaptchaV2Extractor(capSolver)

    val result = extractor.extractWithCaptcha(
        targetUrl = "https://example.com/halaman-terlindungi",
        siteKey = "6LcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxABC"
    )

    println("Hasil ekstraksi: $result")
}

reCAPTCHA v3 dengan Browser4

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

        // Selesaikan reCAPTCHA v3 dengan aksi halaman khusus
        val token = capSolver.solveReCaptchaV3(
            websiteUrl = targetUrl,
            websiteKey = siteKey,
            pageAction = action
        )

        println("Token diperoleh secara sukses")

        // Buat sesi dan buka halaman
        val session = PulsarContexts.createSession()
        val page = session.open(targetUrl)
        val driver = session.getOrCreateBoundDriver()

        // Sisipkan token ke input tersembunyi (menggunakan penugasan nilai yang aman)
        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');
        """)

        // Klik tombol submit
        driver?.evaluate("document.querySelector('#submit-btn').click();")

        Thread.sleep(3000)

        val document = session.parse(page)

        mapOf(
            "result" to document.selectFirstTextOrNull(".result-data"),
            "status" to "success"
        )
    }
}

Cloudflare Turnstile dengan Browser4

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

        // Selesaikan dengan metadata opsional (aksi dan cdata)

val token = capSolver.solveTurnstile(
targetUrl,
siteKey,
action = "login", // opsional
cdata = "0000-1111-2222-3333-example" // opsional
)
println("Turnstile berhasil diselesaikan!")

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

    // Menyuntikkan token Turnstile (menggunakan penugasan nilai yang aman)
    driver?.evaluate("""
        (function(tokenValue) {
            var input = document.querySelector('input[name="cf-turnstile-response"]');
            if (input) input.value = tokenValue;
        })('$token');
    """)

    // Kirim
    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
---

## Integrasi dengan Browser4 X-SQL

Browser4's X-SQL menawarkan kemampuan ekstraksi yang kuat. Berikut cara menggabungkannya dengan penyelesaian CAPTCHA:

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

        // Membuat sesi dan membangun sesi yang terautentikasi
        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)

        // Sekarang parsing halaman dan ekstrak data produk
        val document = session.parse(page)

        // Ekstrak data produk menggunakan metode sesi bawaan
        val products = mutableListOf<Map<String, Any?>>()
        val productElements = document.select(".product-item")

        for ((index, element) in productElements.withIndex()) {
            if (index >= 50) break // BATAS 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"]
            )
        }
    }
}

Pola Pra-Autentikasi

Untuk situs yang memerlukan CAPTCHA sebelum mengakses konten, gunakan alur kerja pra-autentikasi:

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 {
        // Selesaikan CAPTCHA
        val captchaToken = capSolver.solveReCaptchaV2(loginUrl, siteKey)

        // Kirim CAPTCHA untuk mendapatkan cookie sesi
        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()

        // Ekstrak cookie dari respons
        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?> {
        // Pra-autentikasi
        val authSession = preAuth.authenticateWithCaptcha(loginUrl, siteKey)
        println("Sesi berhasil dibuat dengan ${authSession.cookies.size} cookie")

        // Membuat sesi Browser4
        val session = PulsarContexts.createSession()

        // Konfigurasi sesi dengan cookie
        val cookieScript = authSession.cookies.entries.joinToString(";") { (k, v) ->
            "$k=$v"
        }

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

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

        // Muat ulang dengan sesi yang terautentikasi
        driver?.evaluate("location.reload();")
        Thread.sleep(2000)

        // Ekstrak data
        val document = session.parse(page)

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

Integrasi OpenRouter untuk Ekstraksi Berbasis LLM

Kemampuan AI Browser4 dapat ditingkatkan dengan OpenRouter, gateway API yang terpadu untuk mengakses berbagai model LLM. Ini memungkinkan ekstraksi konten yang cerdas yang menyesuaikan diri dengan struktur halaman yang berbeda.

Layanan 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 = """
            Ekstrak data berikut dari konten HTML ini.
            Kembalikan HANYA JSON yang valid sesuai skema ini: $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()
    }
}

Ekstraksi Berbasis LLM dengan Penyelesaian CAPTCHA

Gabungkan penyelesaian CAPTCHA dengan ekstraksi konten yang cerdas:

kotlin Copy
class SmartExtractor(
    private val capSolver: CapSolverService,
    private val openRouter: OpenRouterService
) {
    suspend fun extractWithAI(
        targetUrl: String,
        siteKey: String?,
        extractionPrompt: String
    ): Map<String, Any?> {
        // Langkah 1: Selesaikan CAPTCHA jika diperlukan
        val captchaToken = siteKey?.let {
            println("Menyelesaikan CAPTCHA...")
            capSolver.solveReCaptchaV2(targetUrl, it)
        }

        // Langkah 2: Membuat sesi dan membuka halaman
        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)
        }

        // Langkah 3: Ekstrak konten halaman
        val document = session.parse(page)
        val pageContent = document.body().text().take(8000)

        // Langkah 4: Gunakan LLM untuk ekstraksi data terstruktur
        val llmResponse = openRouter.chat(listOf(
            ChatMessage("system", "Anda adalah asisten ekstraksi data. Ekstrak data terstruktur dari halaman web."),
            ChatMessage("user", """
                $extractionPrompt

                Konten halaman:
                $pageContent
            """.trimIndent())
        ))

        println("LLM menggunakan ${llmResponse.usage.totalTokens} token")

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

// Penggunaan
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 = """
            Ekstrak semua produk dengan:
            - nama
            - harga (sebagai angka)
            - ketersediaan (in_stock/out_of_stock)
            - rating (1-5)
            Kembalikan sebagai array JSON.
        """.trimIndent()
    )

    println("Hasil ekstraksi: ${result["extractedData"]}")
}

Pembuatan Selektor Adaptif

Gunakan LLM untuk menghasilkan selektor CSS untuk struktur halaman yang tidak dikenal:

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?> {
        // Selesaikan CAPTCHA terlebih dahulu
        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');
            """)
        }

        // Dapatkan struktur HTML halaman
        val htmlSample = driver?.evaluate("document.body.innerHTML")?.toString()?.take(5000) ?: ""

        // Minta LLM untuk menghasilkan selektor
        val selectorPrompt = """
            Analisis HTML ini dan berikan selektor CSS untuk bidang berikut: ${dataFields.joinToString(", ")}

            Contoh HTML:
            $htmlSample

            Kembalikan JSON seperti: {"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>

        // Ekstrak menggunakan selektor yang dihasilkan
        val document = session.parse(page)
        val extractedData = selectors.mapValues { (_, selector) ->
            document.selectFirstTextOrNull(selector)
        }

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

Ekstraksi Paralel dengan Korelasi

Desain Browser4 yang selaras dengan korelasi memungkinkan penyelesaian CAPTCHA yang efisien secara paralel:

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>()

        // Kirim semua pekerjaan ke channel
        jobs.forEach { channel.send(it) }
        channel.close()

        // Proses dengan konkurensi terbatas
        val workers = (1..concurrency).map { workerId ->
            async {
                val workerResults = mutableListOf<ExtractionResult>()
                // Setiap pekerja membuat sesi sendiri untuk keamanan thread
                val workerSession = PulsarContexts.createSession()

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

                    try {
                        // Selesaikan CAPTCHA jika kunci situs diberikan
                        val token = job.siteKey?.let {
                            captchaSolved = true
                            capSolver.solveReCaptchaV2(job.url, it)
                        }

                        // Ekstrak data
                        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()
    }
}

// Penggunaan
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("Selesai ${results.size} ekstraksi, selesaikan $solved CAPTCHA")

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

Praktik Terbaik

1. Penanganan Kesalahan dengan Pengulangan

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("Percobaan ${attempt + 1} gagal: ${e.message}")
            delay(initialDelay * (attempt + 1))
        }
    }

    throw lastException ?: Exception("Jumlah pengulangan maksimum tercapai")
}

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

2. Manajemen Saldo

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

    if (balance < minBalance) {
        throw Exception("Saldo CapSolver tidak cukup: $${"%.2f".format(balance)}. Silakan isi ulang.")
    }

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

3. Cache Token

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())
    }
}

// Penggunaan dengan cache
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("Menggunakan token yang dicache")
            return it
        }

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

        return token
    }
}

Opsi Konfigurasi

Pengaturan Deskripsi Nilai Default
CAPSOLVER_API_KEY Kunci API CapSolver Anda -
OPENROUTER_API_KEY Kunci API OpenRouter untuk fitur LLM -
PROXY_ROTATION_URL URL layanan rotasi proxy -
Browser4 menggunakan application.properties untuk konfigurasi tambahan

Kesimpulan

Mengintegrasikan CapSolver dengan Browser4 menciptakan kombinasi yang kuat untuk ekstraksi data web berkecepatan tinggi. Arsitektur Browser4 yang aman korutin dan kemampuan kinerja ekstremnya, dikombinasikan dengan penyelesaian CAPTCHA yang andal dari CapSolver, memungkinkan ekstraksi data dalam skala besar.

Pola integrasi kunci:

  1. Injeksi Token Langsung: Sisipkan token yang diselesaikan melalui evaluasi JavaScript
  2. Pengotentikan Awal: Selesaikan CAPTCHA untuk membangun sesi sebelum ekstraksi
  3. Pemrosesan Paralel: Manfaatkan korutin untuk penyelesaian CAPTCHA yang bersamaan
  4. Integrasi X-SQL: Gabungkan penyelesaian CAPTCHA dengan bahasa query Browser4 yang kuat

Baik Anda membangun sistem pemantauan harga, alur pipa penelitian pasar, atau platform agregasi data, kombinasi Browser4 + CapSolver menyediakan keandalan dan skalabilitas yang diperlukan untuk lingkungan produksi.


Siap memulai? Daftar ke CapSolver dan gunakan kode bonus BROWSER4 untuk bonus tambahan 6% pada recharge pertama Anda!


FAQ

Apa itu Browser4?

Browser4 adalah kerangka kerja otomasi browser berkinerja tinggi dari PulsarRPA yang aman korutin. Dibangun dalam Kotlin dan dirancang untuk ekstraksi data berbasis AI, mendukung 100.000-200.000 kunjungan halaman kompleks per hari per mesin.

Bagaimana CapSolver terintegrasi dengan Browser4?

CapSolver terintegrasi dengan Browser4 melalui kelas layanan yang menyelesaikan CAPTCHA via API CapSolver. Token yang diselesaikan kemudian disisipkan ke halaman menggunakan kemampuan evaluasi JavaScript Browser4 (driver.evaluate()).

Jenis CAPTCHA apa yang bisa diselesaikan CapSolver?

CapSolver mendukung reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, Cloudflare Challenge (5 detik), AWS WAF, GeeTest v3/v4, dan banyak lagi.

Berapa biaya CapSolver?

CapSolver menawarkan harga kompetitif berdasarkan jenis dan volume CAPTCHA yang diselesaikan. Kunjungi capsolver.com untuk harga terkini. Gunakan kode BROWSER4 untuk bonus 6%.

Bahasa pemrograman apa yang digunakan Browser4?

Browser4 dibangun dalam Kotlin dan berjalan di JVM (Java 17+). Browser4 juga bisa digunakan dari aplikasi Java.

Apakah Browser4 bisa menangani penyelesaian CAPTCHA paralel?

Ya! Desain Browser4 yang aman korutin memungkinkan pemrosesan paralel yang efisien. Dengan API CapSolver, Anda bisa menyelesaikan beberapa CAPTCHA secara bersamaan di berbagai pekerjaan ekstraksi.

Bagaimana cara saya menemukan kunci CAPTCHA situs?

Kunci situs biasanya ditemukan dalam sumber HTML halaman:

  • reCAPTCHA: atribut data-sitekey pada elemen .g-recaptcha
  • Turnstile: atribut data-sitekey pada elemen .cf-turnstile
  • Atau periksa permintaan jaringan untuk kunci dalam panggilan API

Pernyataan Kepatuhan: Informasi yang diberikan di blog ini hanya untuk tujuan informasi. CapSolver berkomitmen untuk mematuhi semua hukum dan peraturan yang berlaku. Penggunaan jaringan CapSolver untuk kegiatan ilegal, penipuan, atau penyalahgunaan sangat dilarang dan akan diselidiki. Solusi penyelesaian captcha kami meningkatkan pengalaman pengguna sambil memastikan kepatuhan 100% dalam membantu menyelesaikan kesulitan captcha selama pengambilan data publik. Kami mendorong penggunaan layanan kami secara bertanggung jawab. Untuk informasi lebih lanjut, silakan kunjungi Syarat Layanan dan Kebijakan Privasi.

Lebih lanjut

Maxun dengan Integrasi CapSolver
Cara Menyelesaikan Captcha di Maxun dengan Integrasi CapSolver

Panduan praktis untuk mengintegrasikan CapSolver dengan Maxun dalam penggunaan nyata pengambilan data web. Pelajari cara mengelola reCAPTCHA, Cloudflare Turnstile, dan situs yang dilindungi CAPTCHA dengan menggunakan alur kerja pre-auth dan robot.

web scraping
Logo of CapSolver

Adélia Cruz

21-Jan-2026

Browser4 dengan Integrasi CapSolver
Cara menyelesaikan Captcha di Browser4 dengan integrasi CapSolver

Otomasi Browser4 dengan throughput tinggi dikombinasikan dengan CapSolver untuk menangani tantangan CAPTCHA dalam ekstraksi data web skala besar.

web scraping
Logo of CapSolver

Anh Tuan

21-Jan-2026

Apa Itu Bot Scraping dan Cara Membuatnya
Apa itu Bot Scraping dan Bagaimana Cara Membuatnya

Pelajari apa itu bot scraping dan cara membuatnya untuk ekstraksi data otomatis. Jelajahi alat terbaik, teknik navigasi keamanan, dan praktik scraping yang etis.

web scraping
Logo of CapSolver

Emma Foster

16-Jan-2026

Scrapy vs. Selenium
Scrapy vs. Selenium: Mana yang Terbaik untuk Proyek Scraping Web Anda?

Temukan kekuatan dan perbedaan antara Scrapy dan Selenium untuk pengambilan data web. Pelajari alat mana yang paling sesuai dengan proyek Anda dan cara mengatasi tantangan seperti CAPTCHA.

web scraping
Logo of CapSolver

Emma Foster

14-Jan-2026

Cara Menggunakan Selenium Driverless untuk Web Scraping
Cara Menggunakan Selenium Driverless untuk Pengambilan Data Web yang Efisien

Pelajari cara menggunakan Selenium Driverless untuk pengambilan data web yang efisien. Panduan ini memberikan instruksi langkah demi langkah tentang menyiapkan lingkungan Anda, menulis skrip Selenium Driverless pertama Anda, dan menangani konten dinamis. Mempermudah tugas pengambilan data web Anda dengan menghindari kompleksitas manajemen WebDriver tradisional, sehingga membuat proses ekstraksi data Anda lebih sederhana, lebih cepat, dan lebih portabel.

web scraping
Logo of CapSolver

Aloísio Vítor

14-Jan-2026

Agno dengan Integrasi CapSolver
Cara Menyelesaikan Captcha di Agno dengan Integrasi CapSolver

Pelajari cara mengintegrasikan CapSolver dengan Agno untuk menyelesaikan tantangan reCAPTCHA v2/v3, Cloudflare Turnstile, dan WAF dalam agen AI otonom. Termasuk contoh Python nyata untuk pengambilan data web dan otomatisasi.

web scraping
Logo of CapSolver

Emma Foster

13-Jan-2026