CAPSOLVER
Blog
Integrando Katana com CapSolver: Resolução Automatizada de CAPTCHA para Raspagem de Web

Integração do Katana com o CapSolver: Resolução Automática de CAPTCHA para Web Crawling

Logo of CapSolver

Adélia Cruz

Neural Network Developer

12-Jan-2026

Por que resolver CAPTCHA com Katana usando CapSolver

A raspagem de web é uma técnica essencial para pesquisadores de segurança, testadores de penetração e analistas de dados. No entanto, sites modernos empregam cada vez mais CAPTCHAs para proteger contra acesso automatizado. Este guia demonstra como integrar o Katana, o poderoso framework de raspagem da ProjectDiscovery, com o CapSolver, um serviço líder de resolução de CAPTCHA, para criar uma solução de raspagem robusta que resolva automaticamente os desafios de CAPTCHA.

O que você aprenderá

  • Configurar o Katana no modo navegador sem cabeça
  • Integrar a API do Capsolver para resolução automática de CAPTCHA
  • Lidar com reCAPTCHA v2 e Cloudflare Turnstile
  • Exemplos completos de código para cada tipo de CAPTCHA
  • Boas práticas para raspagem eficiente e responsável

O que é Katana?

Katana é um framework de raspagem web de próxima geração desenvolvido pela ProjectDiscovery. Foi projetado para velocidade e flexibilidade, sendo ideal para reconhecimento de segurança e pipelines de automação.

Principais Funcionalidades

  • Dois Modos de Raspagem: Raspagem baseada em HTTP e automação de navegador sem cabeça
  • Suporte a JavaScript: Analisar e raspar conteúdo renderizado por JavaScript
  • Configuração Flexível: Cabeçalhos personalizados, cookies, preenchimento de formulários e controle de escopo
  • Vários Formatos de Saída: Texto simples, JSON ou JSONL

Instalação

bash Copy
# Requer Go 1.24+
CGO_ENABLED=1 go install github.com/projectdiscovery/katana/cmd/katana@latest

Uso Básico

bash Copy
katana -u https://example.com -headless

O que é Capsolver?

CapSolver é um serviço de resolução de CAPTCHA baseado em inteligência artificial que fornece soluções rápidas e confiáveis para vários tipos de CAPTCHA.

Tipos de CAPTCHA Suportados

  • reCAPTCHA: v2 e versões Enterprise
  • Cloudflare: Turnstile e Challenge
  • AWS WAF: Bypass da proteção WAF
  • E Mais

Fluxo de Trabalho da API

O CapSolver usa um modelo de API baseado em tarefas:

  1. Criar Tarefa: Enviar parâmetros de CAPTCHA (tipo, siteKey, URL)
  2. Obter ID da Tarefa: Receber um identificador único da tarefa
  3. Verificar Resultado: Verificar o status da tarefa até que a solução esteja pronta
  4. Receber Token: Obter o token de CAPTCHA resolvido

Pré-requisitos

Antes de começar, certifique-se de ter:

  1. Go 1.24+ instalado
  2. Chave de API do Capsolver - Registre-se aqui
  3. Navegador Chrome (para modo sem cabeça)

Defina sua chave de API como uma variável de ambiente:

bash Copy
export CAPSOLVER_API_KEY="SUA_CHAVE_DE_API"

Arquitetura de Integração

Copy
┌─────────────────────────┐
│   Aplicação Go        │
│   (navegador go-rod)      │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   Website Alvo        │
│   (com CAPTCHA)        │
└───────────┬─────────────┘
            │
    CAPTCHA Detectado
            │
            ▼
┌─────────────────────────┐
│   Extrair Parâmetros    │
│   (siteKey, URL, tipo)  │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   API do Capsolver     │
│   createTask()          │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   Verificar Resultado   │
│   getTaskResult()       │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   Injetar Token         │
│   na Página             │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   Continuar Raspagem     │
└─────────────────────────┘

Resolvendo reCAPTCHA v2 com o CapSolver

O reCAPTCHA v2 é o tipo de CAPTCHA mais comum, mostrando um checkbox "I'm not a robot" ou desafios de imagem. Aqui está um script completo e executável para resolver o reCAPTCHA v2:

go Copy
// Solucionador de reCAPTCHA v2 - Exemplo Completo
// Uso: go run main.go
// Requer: variável de ambiente 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"
)

// Configuração
var (
	CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
	CAPSOLVER_API     = "https://api.capsolver.com"
)

// Estruturas de resposta da 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 lida com a comunicação da API
type CapsolverClient struct {
	APIKey string
	Client *http.Client
}

// NewCapsolverClient cria um novo cliente do Capsolver
func NewCapsolverClient(apiKey string) *CapsolverClient {
	return &CapsolverClient{
		APIKey: apiKey,
		Client: &http.Client{Timeout: 120 * time.Second},
	}
}

// GetBalance recupera o saldo da conta
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("verificação de saldo falhou")
	}

	return result.Balance, nil
}

// SolveRecaptchaV2 soluciona um desafio de reCAPTCHA v2
func (c *CapsolverClient) SolveRecaptchaV2(websiteURL, siteKey string) (string, error) {
	log.Printf("Criando tarefa de reCAPTCHA v2 para %s", websiteURL)

	// Criar tarefa
	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("falha ao criar tarefa: %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("erro da API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("Tarefa criada: %s", createResult.TaskID)

	// Verificar resultado
	for i := 0; i < 120; i++ {
		result, err := c.getTaskResult(createResult.TaskID)
		if err != nil {
			return "", err
		}

		if result.Status == "ready" {
			log.Printf("CAPTCHA resolvido com sucesso!")
			return result.Solution.GRecaptchaResponse, nil
		}

		if result.Status == "failed" {
			return "", fmt.Errorf("tarefa falhou: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("Aguardando solução... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("tempo esgotado esperando solução")
}

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 extrai a chave do site do reCAPTCHA da HTML da página
func extractSiteKey(html string) string {
	// Procurar atributo 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 injeta o token resolvido na página
func injectRecaptchaToken(page *rod.Page, token string) error {
	js := fmt.Sprintf(`
		(function() {
			// Definir o campo de resposta
			var responseField = document.getElementById('g-recaptcha-response');
			if (responseField) {
				responseField.style.display = 'block';
				responseField.value = '%s';
			}

			// Também definir textareas ocultas
			var textareas = document.querySelectorAll('textarea[name="g-recaptcha-response"]');
			for (var i = 0; i < textareas.length; i++) {
				textareas[i].value = '%s';
			}

			// Disparar callback se existir
			if (typeof ___grecaptcha_cfg !== 'undefined') {
				var clients = ___grecaptcha_cfg.clients;
				for (var key in clients) {
					var client = clients[key];
					if (client) {
						// Tentar encontrar e chamar o 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() {
	// Verificar chave de API
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("A variável de ambiente CAPSOLVER_API_KEY é necessária")
	}

	// URL alvo - página de demonstração do reCAPTCHA da Google
	targetURL := "https://www.google.com/recaptcha/api2/demo"

	log.Println("==============================================")
	log.Println("Katana + Capsolver - Demonstração de reCAPTCHA v2")
	log.Println("==============================================")

	// Inicializar cliente do Capsolver
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// Verificar saldo
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("Aviso: Não foi possível verificar o saldo: %v", err)
	} else {
		log.Printf("Saldo do Capsolver: $%.2f", balance)
	}

	// Iniciar navegador
	log.Println("Iniciando navegador...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(true).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// Navegar até o alvo
	log.Printf("Navegando até: %s", targetURL)
	page := browser.MustPage(targetURL)
	page.MustWaitLoad()
	time.Sleep(2 * time.Second)

	// Obter HTML da página e extrair a chave do site
	html := page.MustHTML()

	// Verificar reCAPTCHA
	if !strings.Contains(html, "g-recaptcha") && !strings.Contains(html, "grecaptcha") {
		log.Fatal("Nenhum reCAPTCHA encontrado na página")
	}

	log.Println("reCAPTCHA detectado!")

	// Extrair chave do site
	siteKey := extractSiteKey(html)
	if siteKey == "" {
		log.Fatal("Não foi possível extrair a chave do site")
	}
	log.Printf("Chave do site: %s", siteKey)

	// Resolver CAPTCHA
	log.Println("Resolvendo CAPTCHA com o Capsolver...")
	token, err := client.SolveRecaptchaV2(targetURL, siteKey)
	if err != nil {
		log.Fatalf("Falha ao resolver CAPTCHA: %v", err)
	}

	log.Printf("Token recebido: %s...", token[:50])

	// Injetar token
	log.Println("Injetando token na página...")
	err = injectRecaptchaToken(page, token)
	if err != nil {
		log.Fatalf("Falha ao injetar token: %v", err)
	}

	// Submeter formulário
	log.Println("Submetendo formulário...")
	submitBtn := page.MustElement("#recaptcha-demo-submit")
	submitBtn.MustClick()

	// Aguardar resultado
	time.Sleep(3 * time.Second)

	// Verificar resultado
	newHTML := page.MustHTML()
	if strings.Contains(newHTML, "Verificação bem-sucedida") || strings.Contains(newHTML, "success") {
		log.Println("==============================================")
		log.Println("SUCESSO! reCAPTCHA resolvido e verificado!")
		log.Println("==============================================")
	} else {
		log.Println("Formulário submetido - verifique a página para o resultado")
	}

	// Obter título da página
	title := page.MustEval(`document.title`).String()
	log.Printf("Título da página final: %s", title)
}

Configuração e Execução

bash Copy
# Criar projeto
mkdir katana-recaptcha-v2
cd katana-recaptcha-v2
go mod init katana-recaptcha-v2

# Instalar dependências
go get github.com/go-rod/rod@latest

# Definir chave de API
export CAPSOLVER_API_KEY="SUA_CHAVE_DE_API"

# Executar
go run main.go

Resolvendo Cloudflare Turnstile com o CapSolver

O Cloudflare Turnstile é uma alternativa de CAPTCHA focada na privacidade. Aqui está um script completo:

go Copy
// Solucionador de Cloudflare Turnstile - Exemplo Completo
// Uso: go run main.go
// Requer: variável de ambiente 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"
)

// Configuração
var (
	CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
	CAPSOLVER_API     = "https://api.capsolver.com"
)

// Estruturas de resposta da 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 lida com a comunicação da API
type CapsolverClient struct {
	APIKey string
	Client *http.Client
}

// NewCapsolverClient cria um novo cliente do Capsolver
func NewCapsolverClient(apiKey string) *CapsolverClient {
	return &CapsolverClient{
		APIKey: apiKey,
		Client: &http.Client{Timeout: 120 * time.Second},
	}
}

// GetBalance recupera o saldo da conta
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 soluciona um desafio de Cloudflare Turnstile
func (c *CapsolverClient) SolveTurnstile(websiteURL, siteKey string) (string, error) {
	log.Printf("Criando tarefa de Turnstile para %s", websiteURL)

	// Criar tarefa
	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("falha ao criar tarefa: %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("erro da API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("Tarefa criada: %s", createResult.TaskID)

	// Verificar resultado
	for i := 0; i < 120; i++ {
		result, err := c.getTaskResult(createResult.TaskID)
		if err != nil {
			return "", err
		}

		if result.Status == "ready" {
			log.Printf("CAPTCHA resolvido com sucesso!")
			return result.Solution.Token, nil
		}

		if result.Status == "failed" {
			return "", fmt.Errorf("tarefa falhou: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("Aguardando solução... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("tempo esgotado esperando solução")
}

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 extrai a chave do site do Cloudflare Turnstile da HTML da página
func extractSiteKey(html string) string {
	// Procurar por atributo 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 ""
}

// injectTurnstileToken injeta o token resolvido na página
func injectTurnstileToken(page *rod.Page, token string) error {
	js := fmt.Sprintf(`
		(function() {
			// Definir o token
			var tokenField = document.querySelector('input[name="cf-turnstile-response"]');
			if (tokenField) {
				tokenField.value = '%s';
			}

			// Ativar o campo de token
			var tokenInput = document.querySelector('input[name="cf-turnstile-response"]');
			if (tokenInput) {
				tokenInput.setAttribute('data-solution', '%s');
				tokenInput.dispatchEvent(new Event('input', { bubbles: true }));
			}

			// Verificar se o token foi injetado
			if (document.querySelector('input[name="cf-turnstile-response"]')) {
				return true;
			} else {
				return false;
			}
		})();
	`, token, token)

	_, err := page.Eval(js)
	return err
}

func main() {
	// Verificar chave de API
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("A variável de ambiente CAPSOLVER_API_KEY é necessária")
	}

	// URL alvo - página de demonstração do Cloudflare Turnstile
	targetURL := "https://cf-turnstile-demo.glitch.me/"

	log.Println("==============================================")
	log.Println("Katana + Capsolver - Demonstração de Cloudflare Turnstile")
	log.Println("==============================================")

	// Inicializar cliente do Capsolver
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// Verificar saldo
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("Aviso: Não foi possível verificar o saldo: %v", err)
	} else {
		log.Printf("Saldo do Capsolver: $%.2f", balance)
	}

	// Iniciar navegador
	log.Println("Iniciando navegador...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(true).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// Navegar até o alvo
	log.Printf("Navegando até: %s", targetURL)
	page := browser.MustPage(targetURL)
	page.MustWaitLoad()
	time.Sleep(2 * time.Second)

	// Obter HTML da página e extrair a chave do site
	html := page.MustHTML()

	// Verificar Cloudflare Turnstile
	if !strings.Contains(html, "cf-turnstile") {
		log.Fatal("Nenhum Cloudflare Turnstile encontrado na página")
	}

	log.Println("Cloudflare Turnstile detectado!")

	// Extrair chave do site
	siteKey := extractSiteKey(html)
	if siteKey == "" {
		log.Fatal("Não foi possível extrair a chave do site")
	}
	log.Printf("Chave do site: %s", siteKey)

	// Resolver CAPTCHA
	log.Println("Resolvendo CAPTCHA com o Capsolver...")
	token, err := client.SolveTurnstile(targetURL, siteKey)
	if err != nil {
		log.Fatalf("Falha ao resolver CAPTCHA: %v", err)
	}

	log.Printf("Token recebido: %s...", token[:50])

	// Injetar token
	log.Println("Injetando token na página...")
	err = injectTurnstileToken(page, token)
	if err != nil {
		log.Fatalf("Falha ao injetar token: %v", err)
	}

	// Submeter formulário
	log.Println("Submetendo formulário...")
	submitBtn := page.MustElement("button[type='submit']")
	submitBtn.MustClick()

	// Aguardar resultado
	time.Sleep(3 * time.Second)

	// Verificar resultado
	newHTML := page.MustHTML()
	if strings.Contains(newHTML, "success") || strings.Contains(newHTML, "Verification Success") {
		log.Println("==============================================")
		log.Println("SUCESSO! Cloudflare Turnstile resolvido e verificado!")
		log.Println("==============================================")
	} else {
		log.Println("Formulário submetido - verifique a página para o resultado")
	}

	// Obter título da página
	title := page.MustEval(`document.title`).String()
	log.Printf("Título da página final: %s", title)
}

"websiteKey": siteKey,
}

Copy
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("falha ao criar tarefa: %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("erro da API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}

log.Printf("Tarefa criada: %s", createResult.TaskID)

// Verificar resultado
for i := 0; i < 120; i++ {
	result, err := c.getTaskResult(createResult.TaskID)
	if err != nil {
		return "", err
	}

	if result.Status == "ready" {
		log.Printf("Turnstile resolvido com sucesso!")
		return result.Solution.Token, nil
	}

	if result.Status == "failed" {
		return "", fmt.Errorf("tarefa falhou: %s", result.ErrorDescription)
	}

	if i%10 == 0 {
		log.Printf("Aguardando solução... (%ds)", i)
	}
	time.Sleep(1 * time.Second)
}

return "", fmt.Errorf("tempo esgotado ao aguardar solução")

}

func (c *CapsolverClient) getTaskResult(taskID string) (*GetTaskResultResponse, error) {
payload := map[string]string{
"clientKey": c.APIKey,
"taskId": taskID,
}

Copy
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 extrai a chave do site Turnstile do HTML da página
func extractTurnstileSiteKey(html string) string {
// Padrão 1: atributo data-sitekey em 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_-]+)['"],
}

Copy
for _, pattern := range patterns {
	re := regexp.MustCompile(pattern)
	matches := re.FindStringSubmatch(html)
	if len(matches) > 1 {
		return matches[1]
	}
}

return ""

}

// injectTurnstileToken injeta o token resolvido na página
func injectTurnstileToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// Definir o campo cf-turnstile-response
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}

Copy
		// Também tentar encontrar por ID
		var byId = document.getElementById('cf-turnstile-response');
		if (byId) {
			byId.value = '%s';
		}

		// Criar campo oculto se necessário
		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);
			}
		}

		// Tentar disparar callback
		if (window.turnstile && window.turnstileCallback) {
			window.turnstileCallback('%s');
		}

		return true;
	})();
`, token, token, token, token)

_, err := page.Eval(js)
return err

}

func main() {
// Verificar chave de API
if CAPSOLVER_API_KEY == "" {
log.Fatal("variável de ambiente CAPSOLVER_API_KEY é obrigatória")
}

Copy
// URL alvo - Substituir por um site que use Cloudflare Turnstile
targetURL := "https://example.com"

log.Println("==============================================")
log.Println("Katana + Capsolver - Demonstração de Turnstile")
log.Println("==============================================")

// Inicializar cliente Capsolver
client := NewCapsolverClient(CAPSOLVER_API_KEY)

// Verificar saldo
balance, err := client.GetBalance()
if err != nil {
	log.Printf("Aviso: Não foi possível verificar o saldo: %v", err)
} else {
	log.Printf("Saldo Capsolver: $%.2f", balance)
}

// Iniciar navegador
log.Println("Iniciando navegador...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()

// Navegar para o alvo
log.Printf("Navegando para: %s", targetURL)
page := browser.MustPage(targetURL)
page.MustWaitLoad()
time.Sleep(2 * time.Second)

// Obter HTML da página
html := page.MustHTML()

// Verificar se há Turnstile
if !strings.Contains(html, "cf-turnstile") && !strings.Contains(html, "turnstile") {
	log.Println("Nenhum Turnstile encontrado na página")
	log.Println("Dica: Substitua targetURL por um site que use Cloudflare Turnstile")
	return
}

log.Println("Turnstile da Cloudflare detectado!")

// Extrair chave do site
siteKey := extractTurnstileSiteKey(html)
if siteKey == "" {
	log.Fatal("Não foi possível extrair a chave do site")
}
log.Printf("Chave do site: %s", siteKey)

// Resolver Turnstile
log.Println("Resolvendo Turnstile com Capsolver...")
token, err := client.SolveTurnstile(targetURL, siteKey)
if err != nil {
	log.Fatalf("Falha ao resolver Turnstile: %v", err)
}

log.Printf("Token recebido: %s...", token[:min(50, len(token))])

// Injetar token
log.Println("Injetando token na página...")
err = injectTurnstileToken(page, token)
if err != nil {
	log.Fatalf("Falha ao injetar token: %v", err)
}

log.Println("==============================================")
log.Println("SUCESSO! Token do Turnstile injetado!")
log.Println("==============================================")

// Obter título da página
title := page.MustEval(`document.title`).String()
log.Printf("Título da página: %s", title)

}

func min(a, b int) int {
if a < b {
return a
}
return b
}

Copy
### Pontos Chave do Turnstile

1. **Tipo de Tarefa**: Use `AntiTurnstileTaskProxyLess`
2. **Campo de Resposta**: O Turnstile usa `cf-turnstile-response` em vez de `g-recaptcha-response`
3. **Resolução Mais Rápida**: O Turnstile geralmente é resolvido mais rápido que o reCAPTCHA (1-10 segundos)
4. **Campo do Token**: A solução está em `solution.token` em vez de `solution.gRecaptchaResponse`

---

## Crawler Universal de CAPTCHA

Aqui está um crawler completo e modular que lida automaticamente com todos os tipos de CAPTCHA:

```go
// Crawler de CAPTCHA Universal - Exemplo Completo
// Detecta e resolve automaticamente reCAPTCHA v2 e Turnstile
// Uso: go run main.go -url "https://example.com"
// Requer: variável de ambiente 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"
)

// ============================================
// Configuração
// ============================================

var (
	CAPSOLVER_API_KEY = os.Getenv("CAPSOLVER_API_KEY")
	CAPSOLVER_API     = "https://api.capsolver.com"
)

// CaptchaType representa diferentes tipos de CAPTCHA
type CaptchaType string

const (
	RecaptchaV2 CaptchaType = "recaptcha_v2"
	Turnstile   CaptchaType = "turnstile"
	Unknown     CaptchaType = "unknown"
)

// CaptchaInfo contém os parâmetros extraídos do CAPTCHA
type CaptchaInfo struct {
	Type    CaptchaType
	SiteKey string
}

// ============================================
// Tipos de 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"`
}

// ============================================
// Cliente 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 *CaptchaInfo, websiteURL string) (string, error) {
	switch info.Type {
	case RecaptchaV2:
		return c.solveRecaptchaV2(websiteURL, info.SiteKey)
	case Turnstile:
		return c.solveTurnstile(websiteURL, info.SiteKey)
	default:
		return "", fmt.Errorf("tipo de CAPTCHA não suportado: %s", info.Type)
	}
}

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) {
	// Criar tarefa
	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("falha ao criar tarefa: %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("erro da API: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("Tarefa criada: %s", createResult.TaskID)

	// Verificar resultado
	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("tarefa falhou: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("Aguardando solução... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("tempo esgotado ao aguardar solução")
}

// ============================================
// Detecção de CAPTCHA
// ============================================

func DetectCaptcha(html string) *CaptchaInfo {
	// Verificar reCAPTCHA v2 (checkbox)
	if strings.Contains(html, "g-recaptcha") {
		siteKey := extractDataSiteKey(html, "g-recaptcha")
		if siteKey != "" {
			return &CaptchaInfo{
				Type:    RecaptchaV2,
				SiteKey: siteKey,
			}
		}
	}

	// Verificar Cloudflare Turnstile
	if strings.Contains(html, "cf-turnstile") || strings.Contains(html, "challenges.cloudflare.com/turnstile") {
		siteKey := extractDataSiteKey(html, "cf-turnstile")
		if siteKey != "" {
			return &CaptchaInfo{
				Type:    Turnstile,
				SiteKey: siteKey,
			}
		}
	}

	return nil
}

func extractDataSiteKey(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]
	}

	// Padrão alternativo
	pattern = fmt.Sprintf(`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*%s`, className)
	re = regexp.MustCompile(pattern)
	matches = re.FindStringSubmatch(html)
	if len(matches) > 1 {
		return matches[1]
	}

	// Padrão genérico para sitekey
	re = regexp.MustCompile(`data-sitekey=['"]([^'"]+)['"]`)
	matches = re.FindStringSubmatch(html)
	if len(matches) > 1 {
		return matches[1]
	}

	return ""
}

// ============================================
// Injeção de Token
// ============================================

func InjectToken(page *rod.Page, token string, captchaType CaptchaType) 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("tipo de CAPTCHA não suportado: %s", captchaType)
	}

	_, err := page.Eval(js)
	return err
}

// ============================================
// Crawler
// ============================================

type CrawlResult struct {
	URL           string
	Title         string
	Success       bool
	CaptchaFound  bool
	CaptchaType   CaptchaType
	CaptchaSolved bool
	Error         string
}

func Crawl(browser *rod.Browser, client *CapsolverClient, targetURL string) *CrawlResult {
	result := &CrawlResult{
		URL:     targetURL,
Sucesso: false,
	}

	// Navegar para o destino
	log.Printf("Navegando para: %s", targetURL)
	page := browser.MustPage(targetURL)
	defer page.MustClose()

	page.MustWaitLoad()
	time.Sleep(2 * time.Second)

	// Obter HTML da página
	html := page.MustHTML()

	// Detectar CAPTCHA
	captchaInfo := DetectCaptcha(html)

	if captchaInfo != nil && captchaInfo.Type != Unknown {
		result.CaptchaFound = true
		result.CaptchaType = captchaInfo.Type

		log.Printf("CAPTCHA detectado: %s (siteKey: %s)", captchaInfo.Type, captchaInfo.SiteKey)

		// Resolver CAPTCHA
		log.Println("Resolvendo CAPTCHA com Capsolver...")
		token, err := client.Solve(captchaInfo, targetURL)
		if err != nil {
			result.Error = fmt.Sprintf("falha ao resolver CAPTCHA: %v", err)
			log.Printf("Erro: %s", result.Error)
			return result
		}

		log.Printf("Token recebido: %s...", token[:min(50, len(token))])

		// Injetar token
		log.Println("Injetando token...")
		err = InjectToken(page, token, captchaInfo.Type)
		if err != nil {
			result.Error = fmt.Sprintf("falha ao injetar token: %v", err)
			log.Printf("Erro: %s", result.Error)
			return result
		}

		result.CaptchaSolved = true
		log.Println("Token injetado com sucesso!")

		// Tentar enviar formulário
		submitForm(page)
		time.Sleep(3 * time.Second)
	} else {
		log.Println("Nenhum CAPTCHA detectado na página")
	}

	// Obter informações da página final
	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("Clicado no botão de envio: %s", selector)
			return
		}
	}
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// ============================================
// Principal
// ============================================

func main() {
	// Analisar flags
	targetURL := flag.String("url", "https://www.google.com/recaptcha/api2/demo", "URL alvo para navegação")
	headless := flag.Bool("headless", true, "Executar o navegador em modo sem cabeça")
	checkBalance := flag.Bool("balance", false, "Verificar apenas o saldo da conta")
	flag.Parse()

	// Verificar chave de API
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("A variável de ambiente CAPSOLVER_API_KEY é obrigatória")
	}

	log.Println("==============================================")
	log.Println("Katana + Capsolver - Crawler Universal de CAPTCHA")
	log.Println("==============================================")

	// Inicializar cliente
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// Verificar saldo
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("Aviso: Não foi possível verificar o saldo: %v", err)
	} else {
		log.Printf("Saldo do Capsolver: $%.2f", balance)
	}

	if *checkBalance {
		return
	}

	// Iniciar navegador
	log.Println("Iniciando navegador...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(*headless).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// Navegar
	result := Crawl(browser, client, *targetURL)

	// Exibir resultados
	log.Println("==============================================")
	log.Println("RESULTADOS DA NAVEGAÇÃO")
	log.Println("==============================================")
	log.Printf("URL: %s", result.URL)
	log.Printf("Título: %s", result.Title)
	log.Printf("Sucesso: %v", result.Success)
	log.Printf("CAPTCHA Detectado: %v", result.CaptchaFound)
	if result.CaptchaFound {
		log.Printf("Tipo de CAPTCHA: %s", result.CaptchaType)
		log.Printf("CAPTCHA Resolvido: %v", result.CaptchaSolved)
	}
	if result.Error != "" {
		log.Printf("Erro: %s", result.Error)
	}
	log.Println("==============================================")
}

Uso

bash Copy
# Criar projeto
mkdir katana-universal-crawler
cd katana-universal-crawler
go mod init katana-universal-crawler

# Instalar dependências
go get github.com/go-rod/rod@latest

# Definir chave de API
export CAPSOLVER_API_KEY="SUA_CHAVE_DE_API"

# Executar com padrão (demonstração reCAPTCHA v2)
go run main.go

# Executar com URL personalizada
go run main.go -url "https://exemplo.com"

# Verificar saldo apenas
go run main.go -balance

# Executar com navegador visível
go run main.go -headless=false

Boas Práticas

1. Otimização de Desempenho

  • Usar tipos de tarefa sem proxy: ReCaptchaV2TaskProxyLess usa proxies internos do Capsolver para resolver mais rapidamente
  • Processamento paralelo: Comece a resolver CAPTCHA enquanto outros elementos da página carregam
  • Cache de tokens: Tokens de reCAPTCHA são válidos por ~2 minutos; cache quando possível

2. Gestão de Custos

  • Detectar antes de resolver: Chame o Capsolver apenas quando um CAPTCHA realmente estiver presente
  • Validar chaves de site: Certifique-se de que as chaves extraídas sejam válidas antes das chamadas à API
  • Monitorar uso: Rastreie chamadas à API para gerenciar custos efetivamente

3. Tratamento de Erros

go Copy
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("Tentativa %d falhou: %v", i+1, err)

        // Backoff exponencial
        time.Sleep(time.Duration(i+1) * time.Second)
    }

    return "", fmt.Errorf("falha após %d tentativas: %w", maxRetries, lastErr)
}

4. Limitação de Taxa

Implemente atrasos apropriados entre solicitações para evitar detecção:

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

Solução de Problemas

Erros Comuns

Erro Causa Solução
ERROR_ZERO_BALANCE Créditos insuficientes Recarregar conta do Capsolver
ERROR_CAPTCHA_UNSOLVABLE Chave de site inválida Verificar lógica de extração
ERROR_INVALID_TASK_DATA Parâmetros ausentes Verificar estrutura da tarefa
context deadline exceeded Tempo limite Aumentar tempo limite ou verificar rede

Dicas de Depuração

  1. Ativar navegador visível: Definir Headless(false) para ver o que está acontecendo
  2. Logar tráfego de rede: Monitorar solicitações para identificar problemas
  3. Salvar capturas de tela: Capturar estado da página para depuração
  4. Validar tokens: Registrar formato do token antes da injeção

Perguntas Frequentes

Q: Posso usar o Katana sem modo sem cabeça para páginas de CAPTCHA?
A: Não, páginas de CAPTCHA exigem renderização de JavaScript, que só funciona no modo sem cabeça.

Q: Por quanto tempo os tokens de CAPTCHA são válidos?
A: Tokens de reCAPTCHA: ~2 minutos. Turnstile: varia conforme configuração.

Q: Qual é o tempo médio de resolução?
A: reCAPTCHA v2: 5-15s, Turnstile: 1-10s.

Q: Posso usar meu próprio proxy?
A: Sim, use tipos de tarefa sem o sufixo "ProxyLess" e forneça a configuração do proxy.


Conclusão

Integrar o Capsolver com o Katana permite lidar com CAPTCHA de forma robusta para suas necessidades de raspagem de web. Os scripts completos acima podem ser copiados diretamente e usados com seus projetos Go.

Pronto para começar? Registre-se no Capsolver e potencialize seus raspadores!

💡 Bônus Exclusivo para Usuários de Integração Katana:
Para comemorar esta integração, oferecemos um código de bônus exclusivo de 6% — Katana para todos os usuários do CapSolver que se registrarem por meio deste tutorial.
Basta inserir o código durante o recarregamento no Dashboard para receber créditos extras de 6% instantaneamente.


12. Documentações

Declaração de Conformidade: As informações fornecidas neste blog são apenas para fins informativos. A CapSolver está comprometida em cumprir todas as leis e regulamentos aplicáveis. O uso da rede CapSolver para atividades ilegais, fraudulentas ou abusivas é estritamente proibido e será investigado. Nossas soluções de resolução de captcha melhoram a experiência do usuário enquanto garantem 100% de conformidade ao ajudar a resolver dificuldades de captcha durante a coleta de dados públicos. Incentivamos o uso responsável de nossos serviços. Para mais informações, visite nossos Termos de Serviço e Política de Privacidade.

Mais

Resolvendo Erros 403 Proibidos ao Raspar Sites com Python
Resolvendo Erros 403 Proibidos ao Raspar Sites com Python

Aprenda como superar erros 403 Proibido ao raspar sites com Python. Este guia aborda rotação de IPs, falsificação de user-agent, limitação de requisições, gerenciamento de autenticação e uso de navegadores headless para contornar restrições de acesso e continuar raspando sites com sucesso.

web scraping
Logo of CapSolver

Emma Foster

13-Jan-2026

Agno com Integração CapSolver
Como resolver CAPTCHA no Agno com integração do CapSolver

Aprenda como integrar o CapSolver com o Agno para resolver desafios de reCAPTCHA v2/v3, Cloudflare Turnstile e WAF em agentes de IA autônomos. Inclui exemplos reais de Python para raspagem de web e automação.

web scraping
Logo of CapSolver

Adélia Cruz

13-Jan-2026

Como resolver CAPTCHA com o Katana usando o CapSolver
Integração do Katana com o CapSolver: Resolução Automática de CAPTCHA para Web Crawling

Aprenda como integrar o Katana com o Capsolver para resolver automaticamente o reCAPTCHA v2 e o Cloudflare Turnstile em raspagem sem cabeça.

web scraping
Logo of CapSolver

Adélia Cruz

12-Jan-2026

Melhores Bibliotecas de Web Scraping em Python 2026
Melhores Bibliotecas de Web Scraping 2026

Descubra as melhores bibliotecas de raspagem de web em Python para 2026. Compare funcionalidades, facilidade de uso e desempenho para suas necessidades de extração de dados. Inclui perspectivas de especialistas e Perguntas Frequentes.

web scraping
Logo of CapSolver

Rajinder Singh

12-Jan-2026

Como resolver Captcha com Crawlab usando CapSolver
Integração do Crawlab com o CapSolver: Resolução Automatizada de CAPTCHA para Raspagem Distribuída

Aprenda como integrar o CapSolver com o Crawlab para resolver reCAPTCHA e Cloudflare Turnstile em escala.

web scraping
Logo of CapSolver

Adélia Cruz

09-Jan-2026

Os Melhores Ferramentas de Raspagem de IA que Você Precisa Conhecer em 2026
Sample Post

Descubra as melhores opções de ferramentas de raspagem de IA para 2026. Comparamos as principais ferramentas de raspagem web de IA, incluindo Bright Data, Crawl4AI e Browse AI, com preços específicos para ajudar você a dominar a extração de dados automatizada e a resolução de desafios de segurança.

web scraping
Logo of CapSolver

Emma Foster

07-Jan-2026