Mengintegrasikan Katana dengan CapSolver: Penyelesaian CAPTCHA Otomatis untuk Penjelajahan Web

Adélia Cruz
Neural Network Developer
12-Jan-2026

Pengambilan data web adalah teknik penting bagi peneliti keamanan, penester penetrasi, dan analis data. Namun, situs web modern semakin menggunakan CAPTCHA untuk melindungi dari akses otomatis. Panduan ini menunjukkan cara mengintegrasikan Katana, kerangka pengambilan data web canggih dari ProjectDiscovery, dengan CapSolver, layanan penyelesaian CAPTCHA terkemuka, untuk menciptakan solusi pengambilan data yang kuat yang secara otomatis menangani tantangan CAPTCHA.
Apa yang Akan Anda Pelajari
- Mengatur Katana dalam mode browser tanpa antarmuka
- Mengintegrasikan API CapSolver untuk penyelesaian CAPTCHA otomatis
- Menangani reCAPTCHA v2 dan Cloudflare Turnstile
- Contoh kode lengkap untuk setiap jenis CAPTCHA
- Praktik terbaik untuk pengambilan data yang efisien dan bertanggung jawab
Apa itu Katana?
Katana adalah kerangka pengambilan data web generasi berikutnya yang dikembangkan oleh ProjectDiscovery. Dirancang untuk kecepatan dan fleksibilitas, membuatnya ideal untuk penelitian keamanan dan pipa otomasi.
Fitur Utama
- Dua Mode Pengambilan Data: Pengambilan data berbasis HTTP dan otomasi browser tanpa antarmuka
- Dukungan JavaScript: Parsing dan pengambilan konten yang dirender JavaScript
- Konfigurasi Fleksibel: Header kustom, cookie, pengisian formulir, dan kontrol skop
- Format Output Banyak: Teks biasa, JSON, atau JSONL
Instalasi
bash
# Memerlukan Go 1.24+
CGO_ENABLED=1 go install github.com/projectdiscovery/katana/cmd/katana@latest
Penggunaan Dasar
bash
katana -u https://example.com -headless
Apa itu CapSolver?
CapSolver adalah layanan penyelesaian CAPTCHA berbasis AI yang menyediakan solusi cepat dan andal untuk berbagai jenis CAPTCHA.
Jenis CAPTCHA yang Didukung
- reCAPTCHA: Versi v2 dan Enterprise
- Cloudflare: Turnstile dan Challenge
- AWS WAF: Bypass perlindungan WAF
- Dan Lainnya
Alur Kerja API
CapSolver menggunakan model API berbasis tugas:
- Buat Tugas: Kirim parameter CAPTCHA (jenis, siteKey, URL)
- Dapatkan ID Tugas: Terima identifikasi tugas unik
- Poll Hasil: Periksa status tugas hingga solusi siap
- Terima Token: Dapatkan token CAPTCHA yang telah diselesaikan
Prasyarat
Sebelum memulai, pastikan Anda memiliki:
- Go 1.24+ terinstal
- Kunci API CapSolver - Daftar di sini
- Browser Chrome (untuk mode tanpa antarmuka)
Atur kunci API sebagai variabel lingkungan:
bash
export CAPSOLVER_API_KEY="KUNCI_API_ANDA"
Arsitektur Integrasi
┌─────────────────────────┐
│ Aplikasi Go │
│ (browser go-rod) │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Situs Target │
│ (dengan CAPTCHA) │
└───────────┬─────────────┘
│
CAPTCHA Terdeteksi
│
▼
┌─────────────────────────┐
│ Ekstrak Parameter │
│ (siteKey, URL, jenis) │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ API CapSolver │
│ createTask() │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Poll Hasil │
│ getTaskResult() │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Masukkan Token │
│ ke Halaman │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐
│ Lanjutkan Pengambilan │
└─────────────────────────┘
Menyelesaikan reCAPTCHA v2 dengan CapSolver
reCAPTCHA v2 adalah jenis CAPTCHA yang paling umum, menampilkan kotak centang "Saya bukan robot" atau tantangan gambar. Berikut adalah skrip lengkap yang dapat dijalankan untuk menyelesaikan reCAPTCHA v2:
go
// Penyelesaian reCAPTCHA v2 - Contoh Lengkap
// Penggunaan: go run main.go
// Memerlukan: variabel lingkungan CAPSOLVER_API_KEY
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
)
// Konfigurasi
var (
CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
CAPSOLVER_API = "https://api.capsolver.com"
)
// Struktur respons API
type CreateTaskResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
TaskID string `json:"taskId"`
}
type GetTaskResultResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
Status string `json:"status"`
Solution struct {
GRecaptchaResponse string `json:"gRecaptchaResponse"`
} `json:"solution"`
}
type BalanceResponse struct {
ErrorID int `json:"errorId"`
Balance float64 `json:"balance"`
}
// CapsolverClient menangani komunikasi API
type CapsolverClient struct {
APIKey string
Client *http.Client
}
// NewCapsolverClient membuat klien CapSolver baru
func NewCapsolverClient(apiKey string) *CapsolverClient {
return &CapsolverClient{
APIKey: apiKey,
Client: &http.Client{Timeout: 120 * time.Second},
}
}
// GetBalance mengambil saldo akun
func (c *CapsolverClient) GetBalance() (float64, error) {
payload := map[string]string{"clientKey": c.APIKey}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getBalance", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result BalanceResponse
json.Unmarshal(body, &result)
if result.ErrorID != 0 {
return 0, fmt.Errorf("pemeriksaan saldo gagal")
}
return result.Balance, nil
}
// SolveRecaptchaV2 menyelesaikan tantangan reCAPTCHA v2
func (c *CapsolverClient) SolveRecaptchaV2(websiteURL, siteKey string) (string, error) {
log.Printf("Membuat tugas reCAPTCHA v2 untuk %s", websiteURL)
// Buat tugas
task := map[string]interface{}{
"type": "ReCaptchaV2TaskProxyLess",
"websiteURL": websiteURL,
"websiteKey": siteKey,
}
payload := map[string]interface{}{
"clientKey": c.APIKey,
"task": task,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/createTask", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("gagal membuat tugas: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var createResult CreateTaskResponse
json.Unmarshal(body, &createResult)
if createResult.ErrorID != 0 {
return "", fmt.Errorf("kesalahan API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}
log.Printf("Tugas dibuat: %s", createResult.TaskID)
// Poll hasil
for i := 0; i < 120; i++ {
result, err := c.getTaskResult(createResult.TaskID)
if err != nil {
return "", err
}
if result.Status == "ready" {
log.Printf("CAPTCHA berhasil diselesaikan!")
return result.Solution.GRecaptchaResponse, nil
}
if result.Status == "failed" {
return "", fmt.Errorf("tugas gagal: %s", result.ErrorDescription)
}
if i%10 == 0 {
log.Printf("Menunggu solusi... (%ds)", i)
}
time.Sleep(1 * time.Second)
}
return "", fmt.Errorf("waktu habis menunggu solusi")
}
func (c *CapsolverClient) getTaskResult(taskID string) (*GetTaskResultResponse, error) {
payload := map[string]string{
"clientKey": c.APIKey,
"taskId": taskID,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getTaskResult", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result GetTaskResultResponse
json.Unmarshal(body, &result)
return &result, nil
}
// extractSiteKey mengekstrak kunci site reCAPTCHA dari HTML halaman
func extractSiteKey(html string) string {
// Cari atribut data-sitekey
patterns := []string{
`data-sitekey="`,
`data-sitekey='`,
`"sitekey":"`,
`'sitekey':'`,
}
for _, pattern := range patterns {
if idx := strings.Index(html, pattern); idx != -1 {
start := idx + len(pattern)
end := start
for end < len(html) && html[end] != '"' && html[end] != '\'' {
end++
}
if end > start {
return html[start:end]
}
}
}
return ""
}
// injectRecaptchaToken menyisipkan token yang telah diselesaikan ke halaman
func injectRecaptchaToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// Atur bidang respons
var responseField = document.getElementById('g-recaptcha-response');
if (responseField) {
responseField.style.display = 'block';
responseField.value = '%s';
}
// Juga atur text area tersembunyi
var textareas = document.querySelectorAll('textarea[name="g-recaptcha-response"]');
for (var i = 0; i < textareas.length; i++) {
textareas[i].value = '%s';
}
// Panggil callback jika ada
if (typeof ___grecaptcha_cfg !== 'undefined') {
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {
var client = clients[key];
if (client) {
// Coba temukan dan panggil callback
try {
var callback = client.callback ||
(client.Q && client.Q.callback) ||
(client.S && client.S.callback);
if (typeof callback === 'function') {
callback('%s');
}
} catch(e) {}
}
}
}
return true;
})();
`, token, token, token)
_, err := page.Eval(js)
return err
}
func main() {
// Periksa kunci API
if CAPSOLVER_API_KEY == "" {
log.Fatal("Variabel lingkungan CAPSOLVER_API_KEY diperlukan")
}
// URL target - halaman demo reCAPTCHA Google
targetURL := "https://www.google.com/recaptcha/api2/demo"
log.Println("==============================================")
log.Println("Katana + Capsolver - Demo reCAPTCHA v2")
log.Println("==============================================")
// Inisialisasi klien Capsolver
client := NewCapsolverClient(CAPSOLVER_API_KEY)
// Periksa saldo
balance, err := client.GetBalance()
if err != nil {
log.Printf("Peringatan: Tidak dapat memeriksa saldo: %v", err)
} else {
log.Printf("Saldo Capsolver: $%.2f", balance)
}
// Jalankan browser
log.Println("Menjalankan browser...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()
// Navigasi ke target
log.Printf("Mengarahkan ke: %s", targetURL)
page := browser.MustPage(targetURL)
page.MustWaitLoad()
time.Sleep(2 * time.Second)
// Dapatkan HTML halaman dan ekstrak kunci site
html := page.MustHTML()
// Periksa reCAPTCHA
if !strings.Contains(html, "g-recaptcha") && !strings.Contains(html, "grecaptcha") {
log.Fatal("Tidak ditemukan reCAPTCHA di halaman")
}
log.Println("reCAPTCHA terdeteksi!")
// Ekstrak kunci site
siteKey := extractSiteKey(html)
if siteKey == "" {
log.Fatal("Tidak dapat mengekstrak kunci site")
}
log.Printf("Kunci site: %s", siteKey)
// Selesaikan CAPTCHA
log.Println("Menyelesaikan CAPTCHA dengan Capsolver...")
token, err := client.SolveRecaptchaV2(targetURL, siteKey)
if err != nil {
log.Fatalf("Gagal menyelesaikan CAPTCHA: %v", err)
}
log.Printf("Token diterima: %s...", token[:50])
// Sisipkan token
log.Println("Menyisipkan token ke halaman...")
err = injectRecaptchaToken(page, token)
if err != nil {
log.Fatalf("Gagal menyisipkan token: %v", err)
}
// Kirim formulir
log.Println("Mengirim formulir...")
submitBtn := page.MustElement("#recaptcha-demo-submit")
submitBtn.MustClick()
// Tunggu hasil
time.Sleep(3 * time.Second)
// Periksa hasil
newHTML := page.MustHTML()
if strings.Contains(newHTML, "Verification Success") || strings.Contains(newHTML, "success") {
log.Println("==============================================")
log.Println("BERHASIL! reCAPTCHA diselesaikan dan diverifikasi!")
log.Println("==============================================")
} else {
log.Println("Formulir dikirim - periksa halaman untuk hasilnya")
}
// Dapatkan judul halaman
title := page.MustEval(`document.title`).String()
log.Printf("Judul halaman akhir: %s", title)
}
Setup dan Jalankan
bash
# Buat proyek
mkdir katana-recaptcha-v2
cd katana-recaptcha-v2
go mod init katana-recaptcha-v2
# Instal dependensi
go get github.com/go-rod/rod@latest
# Atur kunci API
export CAPSOLVER_API_KEY="KUNCI_API_ANDA"
# Jalankan
go run main.go
Menyelesaikan Cloudflare Turnstile dengan CapSolver
Cloudflare Turnstile adalah alternatif CAPTCHA yang fokus pada privasi. Berikut adalah skrip lengkap:
go
// Penyelesaian Cloudflare Turnstile - Contoh Lengkap
// Penggunaan: go run main.go
// Memerlukan: variabel lingkungan CAPSOLVER_API_KEY
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"regexp"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
)
// Konfigurasi
var (
CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
CAPSOLVER_API = "https://api.capsolver.com"
)
// Struktur respons API
type CreateTaskResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
TaskID string `json:"taskId"`
}
type GetTaskResultResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
Status string `json:"status"`
Solution struct {
Token string `json:"token"`
} `json:"solution"`
}
type BalanceResponse struct {
ErrorID int `json:"errorId"`
Balance float64 `json:"balance"`
}
// CapsolverClient menangani komunikasi API
type CapsolverClient struct {
APIKey string
Client *http.Client
}
// NewCapsolverClient membuat klien CapSolver baru
func NewCapsolverClient(apiKey string) *CapsolverClient {
return &CapsolverClient{
APIKey: apiKey,
Client: &http.Client{Timeout: 120 * time.Second},
}
}
// GetBalance mengambil saldo akun
func (c *CapsolverClient) GetBalance() (float64, error) {
payload := map[string]string{"clientKey": c.APIKey}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getBalance", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result BalanceResponse
json.Unmarshal(body, &result)
return result.Balance, nil
}
// SolveTurnstile menyelesaikan tantangan Cloudflare Turnstile
func (c *CapsolverClient) SolveTurnstile(websiteURL, siteKey string) (string, error) {
log.Printf("Membuat tugas Turnstile untuk %s", websiteURL)
// Buat tugas
task := map[string]interface{}{
"type": "AntiTurnstileTaskProxyLess",
"websiteURL": websiteURL,
```
"websiteKey": siteKey,
}
payload := map[string]interface{}{
"clientKey": c.APIKey,
"task": task,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/createTask", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("gagal membuat tugas: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var createResult CreateTaskResponse
json.Unmarshal(body, &createResult)
if createResult.ErrorID != 0 {
return "", fmt.Errorf("kesalahan API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}
log.Printf("Tugas dibuat: %s", createResult.TaskID)
// Memantau hasil
for i := 0; i < 120; i++ {
result, err := c.getTaskResult(createResult.TaskID)
if err != nil {
return "", err
}
if result.Status == "ready" {
log.Printf("Turnstile berhasil diselesaikan!")
return result.Solution.Token, nil
}
if result.Status == "failed" {
return "", fmt.Errorf("tugas gagal: %s", result.ErrorDescription)
}
if i%10 == 0 {
log.Printf("Menunggu solusi... (%ds)", i)
}
time.Sleep(1 * time.Second)
}
return "", fmt.Errorf("waktu habis menunggu solusi")
}
func (c *CapsolverClient) getTaskResult(taskID string) (*GetTaskResultResponse, error) {
payload := map[string]string{
"clientKey": c.APIKey,
"taskId": taskID,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getTaskResult", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result GetTaskResultResponse
json.Unmarshal(body, &result)
return &result, nil
}
// extractTurnstileSiteKey mengekstrak kunci situs Turnstile dari HTML halaman
func extractTurnstileSiteKey(html string) string {
// Pola 1: atribut data-sitekey pada div cf-turnstile
patterns := []string{
`cf-turnstile[^>]*data-sitekey=['"]([^'"]+)['"]`,
`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*cf-turnstile`,
`turnstile\.render\s*\([^,]+,\s*\{[^}]*sitekey['":\s]+['"]([^'"]+)['"]`,
`sitekey['":\s]+['"]([0-9a-zA-Z_-]+)['"]`,
}
for _, pattern := range patterns {
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
}
return ""
}
// injectTurnstileToken menyisipkan token yang dise diselesaikan ke halaman
func injectTurnstileToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// Atur bidang cf-turnstile-response
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}
// Coba cari berdasarkan ID
var byId = document.getElementById('cf-turnstile-response');
if (byId) {
byId.value = '%s';
}
// Buat input tersembunyi jika diperlukan
if (!responseField && !byId) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'cf-turnstile-response';
input.value = '%s';
var form = document.querySelector('form');
if (form) {
form.appendChild(input);
}
}
// Coba memicu callback
if (window.turnstile && window.turnstileCallback) {
window.turnstileCallback('%s');
}
return true;
})();
`, token, token, token, token)
_, err := page.Eval(js)
return err
}
func main() {
// Periksa kunci API
if CAPSOLVER_API_KEY == "" {
log.Fatal("Variabel lingkungan CAPSOLVER_API_KEY diperlukan")
}
// URL target - Ganti dengan situs yang menggunakan Cloudflare Turnstile
targetURL := "https://example.com"
log.Println("==============================================")
log.Println("Katana + Capsolver - Demo Turnstile")
log.Println("==============================================")
// Inisialisasi klien Capsolver
client := NewCapsolverClient(CAPSOLVER_API_KEY)
// Periksa saldo
balance, err := client.GetBalance()
if err != nil {
log.Printf("Peringatan: Tidak dapat memeriksa saldo: %v", err)
} else {
log.Printf("Saldo Capsolver: $%.2f", balance)
}
// Mulai browser
log.Println("Menginisialisasi browser...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()
// Navigasi ke target
log.Printf("Mengunj
"websiteKey": siteKey,
}
payload := map[string]interface{}{
"clientKey": c.APIKey,
"task": task,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/createTask", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("gagal membuat tugas: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var createResult CreateTaskResponse
json.Unmarshal(body, &createResult)
if createResult.ErrorID != 0 {
return "", fmt.Errorf("kesalahan API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}
log.Printf("Tugas dibuat: %s", createResult.TaskID)
// Memantau hasil
for i := 0; i < 120; i++ {
result, err := c.getTaskResult(createResult.TaskID)
if err != nil {
return "", err
}
if result.Status == "ready" {
log.Printf("Turnstile berhasil diselesaikan!")
return result.Solution.Token, nil
}
if result.Status == "failed" {
return "", fmt.Errorf("tugas gagal: %s", result.ErrorDescription)
}
if i%10 == 0 {
log.Printf("Menunggu solusi... (%ds)", i)
}
time.Sleep(1 * time.Second)
}
return "", fmt.Errorf("waktu habis menunggu solusi")
}
func (c *CapsolverClient) getTaskResult(taskID string) (*GetTaskResultResponse, error) {
payload := map[string]string{
"clientKey": c.APIKey,
"taskId": taskID,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getTaskResult", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result GetTaskResultResponse
json.Unmarshal(body, &result)
return &result, nil
}
// extractTurnstileSiteKey mengekstrak kunci situs Turnstile dari HTML halaman
func extractTurnstileSiteKey(html string) string {
// Pola 1: atribut data-sitekey pada div cf-turnstile
patterns := []string{
`cf-turnstile[^>]*data-sitekey=['"]([^'"]+)['"]`,
`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*cf-turnstile`,
`turnstile\.render\s*\([^,]+,\s*\{[^}]*sitekey['":\s]+['"]([^'"]+)['"]`,
`sitekey['":\s]+['"]([0-9a-zA-Z_-]+)['"]`,
}
for _, pattern := range patterns {
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
}
return ""
}
// injectTurnstileToken menyisipkan token yang telah diselesaikan ke halaman
func injectTurnstileToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// Atur bidang cf-turnstile-response
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}
// Coba cari berdasarkan ID
var byId = document.getElementById('cf-turnstile-response');
if (byId) {
byId.value = '%s';
}
// Buat input tersembunyi jika diperlukan
if (!responseField && !byId) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'cf-turnstile-response';
input.value = '%s';
var form = document.querySelector('form');
if (form) {
form.appendChild(input);
}
}
// Coba memicu callback
if (window.turnstile && window.turnstileCallback) {
window.turnstileCallback('%s');
}
return true;
})();
`, token, token, token, token)
_, err := page.Eval(js)
return err
}
func main() {
// Periksa kunci API
if CAPSOLVER_API_KEY == "" {
log.Fatal("Variabel lingkungan CAPSOLVER_API_KEY diperlukan")
}
// URL target - Ganti dengan situs yang menggunakan Cloudflare Turnstile
targetURL := "https://example.com"
log.Println("==============================================")
log.Println("Katana + Capsolver - Demo Turnstile")
log.Println("==============================================")
// Inisialisasi klien Capsolver
client := NewCapsolverClient(CAPSOLVER_API_KEY)
// Periksa saldo
balance, err := client.GetBalance()
if err != nil {
log.Printf("Peringatan: Tidak dapat memeriksa saldo: %v", err)
} else {
log.Printf("Saldo Capsolver: $%.2f", balance)
}
// Mulai browser
log.Println("Menginisialisasi browser...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()
// Navigasi ke target
log.Printf("Mengarahkan ke: %s", targetURL)
page := browser.MustPage(targetURL)
page.MustWaitLoad()
time.Sleep(2 * time.Second)
// Dapatkan HTML halaman
html := page.MustHTML()
// Periksa apakah ada Turnstile
if !strings.Contains(html, "cf-turnstile") && !strings.Contains(html, "turnstile") {
log.Println("Tidak ditemukan Turnstile di halaman")
log.Println("Pet
"websiteKey": siteKey,
}
payload := map[string]interface{}{
"clientKey": c.APIKey,
"task": task,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/createTask", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("gagal membuat tugas: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var createResult CreateTaskResponse
json.Unmarshal(body, &createResult)
if createResult.ErrorID != 0 {
return "", fmt.Errorf("kesalahan API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}
log.Printf("Tugas dibuat: %s", createResult.TaskID)
// Memantau hasil
for i := 0; i < 120; i++ {
result, err := c.getTaskResult(createResult.TaskID)
if err != nil {
return "", err
}
if result.Status == "ready" {
log.Printf("Turnstile berhasil diselesaikan!")
return result.Solution.Token, nil
}
if result.Status == "failed" {
return "", fmt.Errorf("tugas gagal: %s", result.ErrorDescription)
}
if i%10 == 0 {
log.Printf("Menunggu solusi... (%ds)", i)
}
time.Sleep(1 * time.Second)
}
return "", fmt.Errorf("waktu habis menunggu solusi")
}
func (c *CapsolverClient) getTaskResult(taskID string) (*GetTaskResultResponse, error) {
payload := map[string]string{
"clientKey": c.APIKey,
"taskId": taskID,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getTaskResult", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result GetTaskResultResponse
json.Unmarshal(body, &result)
return &result, nil
}
// extractTurnstileSiteKey mengekstrak kunci situs Turnstile dari HTML halaman
func extractTurnstileSiteKey(html string) string {
// Pola 1: atribut data-sitekey pada div cf-turnstile
patterns := []string{
`cf-turnstile[^>]*data-sitekey=['"]([^'"]+)['"]`,
`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*cf-turnstile`,
`turnstile\.render\s*\([^,]+,\s*\{[^}]*sitekey['":\s]+['"]([^'"]+)['"]`,
`sitekey['":\s]+['"]([0-9a-zA-Z_-]+)['"]`,
}
for _, pattern := range patterns {
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
}
return ""
}
// injectTurnstileToken menyisipkan token yang telah diselesaikan ke halaman
func injectTurnstileToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// Atur bidang cf-turnstile-response
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}
// Coba cari berdasarkan ID
var byId = document.getElementById('cf-turnstile-response');
if (byId) {
byId.value = '%s';
}
// Buat input tersembunyi jika diperlukan
if (!responseField && !byId) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'cf-turnstile-response';
input.value = '%s';
var form = document.querySelector('form');
if (form) {
form.appendChild(input);
}
}
// Coba memicu callback
if (window.turnstile && window.turnstileCallback) {
window.turnstileCallback('%s');
}
return true;
})();
`, token, token, token, token)
_, err := page.Eval(js)
return err
}
func main() {
// Periksa kunci API
if CAPSOLVER_API_KEY == "" {
log.Fatal("Variabel lingkungan CAPSOLVER_API_KEY diperlukan")
}
// URL target - Ganti dengan situs yang menggunakan Cloudflare Turnstile
targetURL := "https://example.com"
log.Println("==============================================")
log.Println("Katana + Capsolver - Demo Turnstile")
log.Println("==============================================")
// Inisialisasi klien Capsolver
client := NewCapsolverClient(CAPSOLVER_API_KEY)
// Periksa saldo
balance, err := client.GetBalance()
if err != nil {
log.Printf("Peringatan: Tidak dapat memeriksa saldo: %v", err)
} else {
log.Printf("Saldo Capsolver: $%.2f", balance)
}
// Mulai browser
log.Println("Menginisialisasi browser...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()
// Navigasi ke target
log.Printf("Mengarahkan ke: %s", targetURL)
page := browser.MustPage(targetURL)
page.MustWaitLoad()
time.Sleep(2 * time.Second)
// Dapatkan HTML halaman
html := page.MustHTML()
// Periksa apakah ada Turnstile
if !strings.Contains(html, "cf-turnstile") && !strings.Contains(html, "turnstile") {
log.Println("Tidak ditemukan Turnstile di halaman")
log.Println("Petunjuk: Ganti targetURL dengan situs yang menggunakan Cloudflare Turnstile")
return
}
log.Println("Cloudflare Turnstile ditemukan!")
// Ekstrak kunci situs
siteKey := extractTurnstileSiteKey(html)
if siteKey == "" {
log.Fatal("Tidak dapat mengekstrak kunci situs")
}
log.Printf("Kunci situs: %s", siteKey)
// Selesaikan Turnstile
log.Println("Menyelesaikan Turnstile dengan Capsolver...")
token, err := client.SolveTurnstile(targetURL, siteKey)
if err != nil {
log.Fatalf("Gagal menyelesaikan Turnstile: %v", err)
}
log.Printf("Token diterima: %s...", token[:min(50, len(token))])
// Sisipkan token
log.Println("Menyisipkan token ke halaman...")
err = injectTurnstileToken(page, token)
if err != nil {
log.Fatalf("Gagal menyisipkan token: %v", err)
}
log.Println("==============================================")
log.Println("BERHASIL! Token Turnstile disisipkan!")
log.Println("==============================================")
// Dapatkan judul halaman
title := page.MustEval(`document.title`).String()
log.Printf("Judul halaman: %s", title)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
Poin-Poin Turnstile
- Jenis Tugas: Gunakan
AntiTurnstileTaskProxyLess - Bidang Respons: Turnstile menggunakan
cf-turnstile-responsealih-alihg-recaptcha-response - Pemecahan Lebih Cepat: Turnstile biasanya lebih cepat dibandingkan reCAPTCHA (1-10 detik)
- Bidang Token: Solusi ada di
solution.tokenalih-alihsolution.gRecaptchaResponse
Pengumpul CAPTCHA Universal
Berikut adalah crawler lengkap dan modular yang menangani semua jenis CAPTCHA secara otomatis:
go
// Pengumpul CAPTCHA Universal - Contoh Lengkap
// Menangani secara otomatis reCAPTCHA v2 dan Turnstile
// Penggunaan: go run main.go -url "https://example.com"
// Membutuhkan: variabel lingkungan CAPSOLVER_API_KEY
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"regexp"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
)
// ============================================
// Konfigurasi
// ============================================
var (
CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
CAPSOLVER_API = "https://api.capsolver.com"
)
// JenisCAPTCHA merepresentasikan berbagai jenis CAPTCHA
type JenisCAPTCHA string
const (
ReCAPTCHAv2 JenisCAPTCHA = "recaptcha_v2"
Turnstile JenisCAPTCHA = "turnstile"
Unknown JenisCAPTCHA = "unknown"
)
// InformasiCAPTCHA berisi parameter CAPTCHA yang diekstrak
type InformasiCAPTCHA struct {
Jenis JenisCAPTCHA
SiteKey string
}
// ============================================
// Tipe API
// ============================================
type CreateTaskResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
TaskID string `json:"taskId"`
}
type GetTaskResultResponse struct {
ErrorID int `json:"errorId"`
ErrorCode string `json:"errorCode"`
ErrorDescription string `json:"errorDescription"`
Status string `json:"status"`
Solution struct {
GRecaptchaResponse string `json:"gRecaptchaResponse"`
Token string `json:"token"`
} `json:"solution"`
}
type BalanceResponse struct {
ErrorID int `json:"errorId"`
Balance float64 `json:"balance"`
}
// ============================================
// Klien Capsolver
// ============================================
type CapsolverClient struct {
APIKey string
Client *http.Client
}
func NewCapsolverClient(apiKey string) *CapsolverClient {
return &CapsolverClient{
APIKey: apiKey,
Client: &http.Client{Timeout: 120 * time.Second},
}
}
func (c *CapsolverClient) GetBalance() (float64, error) {
payload := map[string]string{"clientKey": c.APIKey}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getBalance", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return 0, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result BalanceResponse
json.Unmarshal(body, &result)
return result.Balance, nil
}
func (c *CapsolverClient) Solve(info *InformasiCAPTCHA, websiteURL string) (string, error) {
switch info.Jenis {
case ReCAPTCHAv2:
return c.solveReCAPTCHAv2(websiteURL, info.SiteKey)
case Turnstile:
return c.solveTurnstile(websiteURL, info.SiteKey)
default:
return "", fmt.Errorf("jenis CAPTCHA tidak didukung: %s", info.Jenis)
}
}
func (c *CapsolverClient) solveReCAPTCHAv2(websiteURL, siteKey string) (string, error) {
task := map[string]interface{}{
"type": "ReCaptchaV2TaskProxyLess",
"websiteURL": websiteURL,
"websiteKey": siteKey,
}
return c.solveTask(task, "recaptcha")
}
func (c *CapsolverClient) solveTurnstile(websiteURL, siteKey string) (string, error) {
task := map[string]interface{}{
"type": "AntiTurnstileTaskProxyLess",
"websiteURL": websiteURL,
"websiteKey": siteKey,
}
return c.solveTask(task, "turnstile")
}
func (c *CapsolverClient) solveTask(task map[string]interface{}, tokenType string) (string, error) {
// Membuat tugas
payload := map[string]interface{}{
"clientKey": c.APIKey,
"task": task,
}
jsonData, _ := json.Marshal(payload)
resp, err := c.Client.Post(CAPSOLVER_API+"/createTask", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("gagal membuat tugas: %w", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var createResult CreateTaskResponse
json.Unmarshal(body, &createResult)
if createResult.ErrorID != 0 {
return "", fmt.Errorf("kesalahan API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}
log.Printf("Tugas dibuat: %s", createResult.TaskID)
// Memantau hasil
for i := 0; i < 120; i++ {
getPayload := map[string]string{
"clientKey": c.APIKey,
"taskId": createResult.TaskID,
}
jsonData, _ := json.Marshal(getPayload)
resp, err := c.Client.Post(CAPSOLVER_API+"/getTaskResult", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return "", err
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var result GetTaskResultResponse
json.Unmarshal(body, &result)
if result.Status == "ready" {
if tokenType == "turnstile" {
return result.Solution.Token, nil
}
return result.Solution.GRecaptchaResponse, nil
}
if result.Status == "failed" {
return "", fmt.Errorf("tugas gagal: %s", result.ErrorDescription)
}
if i%10 == 0 {
log.Printf("Menunggu solusi... (%ds)", i)
}
time.Sleep(1 * time.Second)
}
return "", fmt.Errorf("waktu habis menunggu solusi")
}
// ============================================
// Deteksi CAPTCHA
// ============================================
func DeteksiCAPTCHA(html string) *InformasiCAPTCHA {
// Periksa re reCAPTCHA v2 (checkbox)
if strings.Contains(html, "g-recaptcha") {
siteKey := ekstrakDataSiteKey(html, "g-recaptcha")
if siteKey != "" {
return &InformasiCAPTCHA{
Jenis: ReCAPTCHAv2,
SiteKey: siteKey,
}
}
}
// Periksa untuk Cloudflare Turnstile
if strings.Contains(html, "cf-turnstile") || strings.Contains(html, "challenges.cloudflare.com/turnstile") {
siteKey := ekstrakDataSiteKey(html, "cf-turnstile")
if siteKey != "" {
return &InformasiCAPTCHA{
Jenis: Turnstile,
SiteKey: siteKey,
}
}
}
return nil
}
func ekstrakDataSiteKey(html, className string) string {
pattern := fmt.Sprintf(`class=['"][^'"]*%s[^'"]*['"][^>]*data-sitekey=['"]([^'"]+)['"]`, className)
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
// Pola alternatif
pattern = fmt.Sprintf(`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*%s`, className)
re = regexp.MustCompile(pattern)
matches = re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
// Pola umum untuk sitekey
re = regexp.MustCompile(`data-sitekey=['"]([^'"]+)['"]`)
matches = re.FindStringSubmatch(html)
if len(matches) > 1 {
return matches[1]
}
return ""
}
// ============================================
// Penyisipan Token
// ============================================
func SisipkanToken(page *rod.Page, token string, captchaType JenisCAPTCHA) error {
var js string
switch captchaType {
case ReCAPTCHAv2:
js = fmt.Sprintf(`
(function() {
var responseField = document.getElementById('g-recaptcha-response');
if (responseField) {
responseField.style.display = 'block';
responseField.value = '%s';
}
var textareas = document.querySelectorAll('textarea[name="g-recaptcha-response"]');
for (var i = 0; i < textareas.length; i++) {
textareas[i].value = '%s';
}
if (typeof ___grecaptcha_cfg !== 'undefined') {
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {
var client = clients[key];
if (client) {
try {
var callback = client.callback ||
(client.Q && client.Q.callback) ||
(client.S && client.S.callback);
if (typeof callback === 'function') {
callback('%s');
}
} catch(e) {}
}
}
}
return true;
})();
`, token, token, token)
case Turnstile:
js = fmt.Sprintf(`
(function() {
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}
if (!responseField) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'cf-turnstile-response';
input.value = '%s';
var form = document.querySelector('form');
if (form) form.appendChild(input);
}
if (window.turnstile && window.turnstileCallback) {
window.turnstileCallback('%s');
}
return true;
})();
`, token, token, token)
default:
return fmt.Errorf("jenis CAPTCHA tidak didukung: %s", captchaType)
}
_, err := page.Eval(js)
return err
}
// ============================================
// Crawler
// ============================================
type HasilCrawl struct {
URL string
Judul string
Keberhasilan bool
CAPTCHAFound bool
CAPTCHAType JenisCAPTCHA
CAPTCHASolved bool
Kesalahan string
}
func Crawl(browser *rod.Browser, client *CapsolverClient, targetURL string) *HasilCrawl {
result := &HasilCrawl{
URL: targetURL,
Berhasil: false,
}
// Navigasi ke target
log.Printf("Navigasi ke: %s", targetURL)
page := browser.MustPage(targetURL)
defer page.MustClose()
page.MustWaitLoad()
time.Sleep(2 * time detik)
// Dapatkan HTML halaman
html := page.MustHTML()
// Deteksi CAPTCHA
captchaInfo := DetectCaptcha(html)
if captchaInfo != nil && captchaInfo.Type != Unknown {
result.CaptchaFound = true
result.CaptchaType = captchaInfo.Type
log.Printf("CAPTCHA terdeteksi: %s (siteKey: %s)", captchaInfo.Type, captchaInfo.SiteKey)
// Selesaikan CAPTCHA
log.Println("Menyelesaikan CAPTCHA dengan Capsolver...")
token, err := client.Solve(captchaInfo, targetURL)
if err != nil {
result.Error = fmt.Sprintf("gagal menyelesaikan CAPTCHA: %v", err)
log.Printf("Kesalahan: %s", result.Error)
return result
}
log.Printf("Token diterima: %s...", token[:min(50, len(token))])
// Sisipkan token
log.Println("Menyisipkan token...")
err = InjectToken(page, token, captchaInfo.Type)
if err != nil {
result.Error = fmt.Sprintf("gagal menyisipkan token: %v", err)
log.Printf("Kesalahan: %s", result.Error)
return result
}
result.CaptchaSolved = true
log.Println("Token berhasil disisipkan!")
// Coba kirim formulir
submitForm(page)
time.Sleep(3 * time detik)
} else {
log.Println("Tidak ada CAPTCHA yang terdeteksi di halaman")
}
// Dapatkan informasi halaman akhir
result.Title = page.MustEval(`document.title`).String()
result.Success = true
return result
}
func submitForm(page *rod.Page) {
selectors := []string{
"button[type='submit']",
"input[type='submit']",
"#recaptcha-demo-submit",
".submit-button",
}
for _, selector := range selectors {
js := fmt.Sprintf(`
(function() {
var btn = document.querySelector('%s');
if (btn && btn.offsetParent !== null) {
btn.click();
return true;
}
return false;
})();
`, selector)
result := page.MustEval(js)
if result.Bool() {
log.Printf("Klik tombol submit: %s", selector)
return
}
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
// ============================================
// Utama
// ============================================
func main() {
// Parsing flag
targetURL := flag.String("url", "https://www.google.com/recaptcha/api2/demo", "URL target untuk dijelajahi")
headless := flag.Bool("headless", true, "Jalankan browser dalam mode headless")
checkBalance := flag.Bool("balance", false, "Hanya periksa saldo akun")
flag.Parse()
// Periksa kunci API
if CAPSOLVER_API_KEY == "" {
log.Fatal("Variabel lingkungan CAPSOLVER_API_KEY diperlukan")
}
log.Println("==============================================")
log.Println("Katana + Capsolver - Pengejelajah CAPTCHA Universal")
log.Println("==============================================")
// Inisialisasi klien
client := NewCapsolverClient(CAPSOLVER_API_KEY)
// Periksa saldo
balance, err := client.GetBalance()
if err != nil {
log.Printf("Peringatan: Tidak dapat memeriksa saldo: %v", err)
} else {
log.Printf("Saldo Capsolver: $%.2f", balance)
}
if *checkBalance {
return
}
// Jalankan browser
log.Println("Menginisialisasi browser...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(*headless).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()
// Jelajahi
result := Crawl(browser, client, *targetURL)
// Output hasil
log.Println("==============================================")
log.Println("HASIL PENJELAJAHAN")
log.Println("==============================================")
log.Printf("URL: %s", result.URL)
log.Printf("Judul: %s", result.Title)
log.Printf("Berhasil: %v", result.Success)
log.Printf("CAPTCHA Ditemukan: %v", result.CaptchaFound)
if result.CaptchaFound {
log.Printf("Jenis CAPTCHA: %s", result.CaptchaType)
log.Printf("CAPTCHA Diselesaikan: %v", result.CaptchaSolved)
}
if result.Error != "" {
log.Printf("Kesalahan: %s", result.Error)
}
log.Println("==============================================")
}
### Penggunaan
```bash
# Buat proyek
mkdir katana-universal-crawler
cd katana-universal-crawler
go mod init katana-universal-crawler
# Instal dependensi
go get github.com/go-rod/rod@latest
# Atur kunci API
export CAPSOLVER_API_KEY="KUNCI_API_ANDA"
# Jalankan dengan default (demo reCAPTCHA v2)
go run main.go
# Jalankan dengan URL kustom
go run main.go -url "https://example.com"
# Periksa saldo saja
go run main.go -balance
# Jalankan dengan browser yang terlihat
go run main.go -headless=false
Praktik Terbaik
1. Optimisasi Kinerja
- Gunakan Tipe Tugas ProxyLess:
ReCaptchaV2TaskProxyLessmenggunakan proxy internal Capsolver untuk penyelesaian yang lebih cepat - Pemrosesan Paralel: Mulai penyelesaian CAPTCHA saat elemen halaman lain dimuat
- Penyimpanan Token: Token reCAPTCHA berlaku selama ~2 menit; simpan jika memungkinkan
2. Pengelolaan Biaya
- Deteksi Sebelum Menyelesaikan: Hanya panggil Capsolver ketika CAPTCHA benar-benar hadir
- Validasi Site Keys: Pastikan kunci yang diekstrak valid sebelum panggilan API
- Pantau Penggunaan: Lacak panggilan API untuk mengelola biaya secara efektif
3. Penanganan Kesalahan
go
func SolveWithRetry(client *CapsolverClient, info *CaptchaInfo, url string, maxRetries int) (string, error) {
var lastErr error
for i := 0; i < maxRetries; i++ {
token, err := client.Solve(info, url)
if err == nil {
return token, nil
}
lastErr = err
log.Printf("Percobaan %d gagal: %v", i+1, err)
// Backoff eksponensial
time.Sleep(time.Duration(i+1) * time detik)
}
return "", fmt.Errorf("gagal setelah %d percobaan: %w", maxRetries, lastErr)
}
4. Pembatasan Kecepatan
Implementasikan penundaan yang sesuai antara permintaan untuk menghindari deteksi:
go
type RateLimiter struct {
requests int
interval time.Duration
lastRequest time.Time
mu sync.Mutex
}
func (r *RateLimiter) Wait() {
r.mu.Lock()
defer r.mu.Unlock()
elapsed := time.Since(r.lastRequest)
if elapsed < r.interval {
time.Sleep(r.interval - elapsed)
}
r.lastRequest = time.Now()
}
Pemecahan Masalah
Kesalahan Umum
| Kesalahan | Penyebab | Solusi |
|---|---|---|
ERROR_ZERO_BALANCE |
Kredit tidak cukup | Isi ulang akun Capsolver |
ERROR_CAPTCHA_UNSOLVABLE |
Kunci situs tidak valid | Periksa logika ekstraksi |
ERROR_INVALID_TASK_DATA |
Parameter hilang | Periksa struktur tugas |
context deadline exceeded |
Waktu habis | Tingkatkan waktu tunggu atau periksa jaringan |
Tips Pemecahan Masalah
- Aktifkan Browser yang Terlihat: Setel
Headless(false)untuk melihat apa yang terjadi - Lacak Lalu Lintas Jaringan: Pantau permintaan untuk mengidentifikasi masalah
- Simpan Tangkapan Layar: Tangkap status halaman untuk debugging
- Validasi Token: Catat format token sebelum penyisipan
FAQ
T: Bisakah saya menggunakan Katana tanpa mode headless untuk halaman CAPTCHA?
J: Tidak, halaman CAPTCHA memerlukan rendering JavaScript yang hanya bekerja dalam mode headless.
T: Berapa lama token CAPTCHA berlaku?
J: Token reCAPTCHA: ~2 menit. Turnstile: tergantung konfigurasi.
T: Berapa waktu rata-rata penyelesaian?
J: reCAPTCHA v2: 5-15 detik, Turnstile: 1-10 detik.
T: Bisakah saya menggunakan proxy sendiri?
J: Ya, gunakan tipe tugas tanpa kata "ProxyLess" dan berikan konfigurasi proxy.
Kesimpulan
Mengintegrasikan Capsolver dengan Katana memungkinkan penanganan CAPTCHA yang andal untuk kebutuhan penjelajahan web Anda. Skrip lengkap di atas dapat dicopy langsung dan digunakan dengan proyek Go Anda.
Siap mulai? Daftar di Capsolver dan tingkatkan crawler Anda!
💡 Bonus Eksklusif untuk Pengguna Integrasi Katana:
Untuk merayakan integrasi ini, kami menawarkan kode bonus 6% — Katana untuk semua pengguna Capsolver yang mendaftar melalui tutorial ini.
Cukup masukkan kode saat recharge di Dashboard untuk menerima tambahan 6% kredit secara instan.
12. Dokumentasi
- 12.1. Repositori GitHub Katana
- 12.2. Dokumentasi Katana
- 12.3. Dokumentasi Capsolver
- 12.4. Pengotomatan Browser Go Rod
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

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.

Emma Foster
13-Jan-2026

Mengintegrasikan Katana dengan CapSolver: Penyelesaian CAPTCHA Otomatis untuk Penjelajahan Web
Pelajari cara mengintegrasikan Katana dengan Capsolver untuk secara otomatis menyelesaikan reCAPTCHA v2 dan Cloudflare Turnstile dalam crawling headless.

Adélia Cruz
12-Jan-2026

Pustaka Scraping Web Python Teratas 2026
Jelajahi perpustakaan web scraping Python terbaik untuk 2026. Bandingkan fitur, kemudahan penggunaan, dan kinerja untuk kebutuhan ekstraksi data Anda. Termasuk wawasan ahli dan FAQ.

Anh Tuan
12-Jan-2026

Mengintegrasikan Crawlab dengan CapSolver: Penyelesaian CAPTCHA Otomatis untuk Penjelajahan Terdistribusi
Pelajari cara mengintegrasikan CapSolver dengan Crawlab untuk menyelesaikan reCAPTCHA dan Cloudflare Turnstile secara skala.

Ethan Collins
09-Jan-2026

Alat Scraping AI Terbaik yang Harus Anda Ketahui pada 2026
Temukan pilihan alat scraping AI terbaik untuk 2026. Kami membandingkan alat scraping web AI terbaik, termasuk Bright Data, Crawl4AI, dan Browse AI, dengan harga spesifik untuk membantu Anda menguasai ekstraksi data otomatis dan penyelesaian tantangan keamanan.

Emma Foster
07-Jan-2026

Penyedia Data Alternatif Terbaik pada 2026 (Platform Terbaik Dibandingkan)
Temukan Penyedia Data Alternatif Terbaik pada 2026. Panduan kami membandingkan platform teratas (YipitData, FactSet, Preqin) dengan kelebihan, kekurangan, dan wawasan harga untuk kepatuhan dan penghasilan alpha.

Emma Foster
06-Jan-2026


