CAPSOLVER
ブログ
KatanaとCapSolverの統合: ウェブクローリング用の自動CAPTCHA解決

カタナとキャップソルバーの統合: ウェブクローリング用の自動CAPTCHA解決

Logo of CapSolver

Sora Fujimoto

AI Solutions Architect

12-Jan-2026

KatanaとCapSolverを使用してCAPTCHAを解決する方法

ウェブクローリングは、セキュリティ研究者、ペネトレーションテスター、データアナリストにとって重要な技術です。しかし、現代のウェブサイトはますます自動アクセスを防ぐためにCAPTCHAを採用しています。このガイドでは、Katana(ProjectDiscoveryの強力なウェブクローラー)とCapSolver(リーディングなCAPTCHA解決サービス)を統合し、自動的にCAPTCHAチャレンジを処理する堅牢なクローリングソリューションを構築する方法を紹介します。

学ぶ内容

  • ヘッドレスブラウザモードでのKatanaの設定
  • CapSolverのAPIを自動CAPTCHA解決に統合
  • reCAPTCHA v2とCloudflare Turnstileの処理
  • 各CAPTCHAタイプの完全な実行可能なコード例
  • 効率的で責任あるクローリングのベストプラクティス

什麼Katana?

Katana は、ProjectDiscoveryによって開発された次世代のウェブクローリングフレームワークです。高速で柔軟性があり、セキュリティ調査と自動化パイプラインに最適です。

主な特徴

  • 2つのクローリングモード: 通常のHTTPベースのクローリングとヘッドレスブラウザの自動化
  • JavaScriptサポート: JavaScriptでレンダリングされたコンテンツを解析・クロール
  • 柔軟な設定: カスタムヘッダー、クッキー、フォーム入力、スコープ制御
  • 複数の出力形式: テキスト、JSON、またはJSONL

インストール

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

基本的な使い方

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

什么是CapSolver?

CapSolver は、AIを活用したCAPTCHA解決サービスで、さまざまなタイプのCAPTCHAに高速かつ信頼性高く対応します。

サポートされているCAPTCHAタイプ

  • reCAPTCHA: v2とEnterpriseバージョン
  • Cloudflare: TurnstileとChallenge
  • AWS WAF: WAF保護の回避
  • およびその他

APIワークフロー

CapSolverはタスクベースのAPIモデルを使用します:

  1. タスクの作成: CAPTCHAパラメータ(タイプ、siteKey、URL)を送信
  2. タスクIDの取得: 一意のタスク識別子を受信
  3. 結果のポーリング: ソリューションが準備できるまでタスクステータスを確認
  4. トークンの取得信: 解決されたCAPTCHAトークンを取得

必要条件

開始する前に、以下の項目確認してください:

  1. **Go 1.24+**がインストールされていること
  2. CapSolver APIキー - 登に登録
  3. Chromeブラウザ(ヘッドレスモード用)

APIキーを環境変数として設定してください:

bash Copy
export CAPSOLVER_API_KEY="YOUR_API_KEY"

結合アーキテクチャ

Copy
┌─────────────────────────┐
│   Goアプリケーション     │
│   (go-rodブラウザ)      │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   ターゲットウェブサイト │
│   (CAPTCHAあり)         │
└───────────┬─────────────┘
            │
    CAPTCHA検出
            │
            ▼
┌─────────────────────────┐
│   パラメータの抽出      │
│   (siteKey、URL、タイプ) │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   CapSolver API         │
│   createTask()          │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   結果のポーリング       │
│   getTaskResult()       │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   トークンの挿入         │
│   ページに注入          │
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   クローリングを継続     │
└─────────────────────────┘

CapSolverでreCAPTCHA v2を解決する方法

reCAPTCHA v2は最も一般的なCAPTCHAタイプで、「I'm not a robot」チェックボックスや画像チャレンジを表示します。以下はreCAPTCHA v2を解決する完全な実行可能なスクリプトです:

go Copy
// reCAPTCHA v2 ソルバー - 完全な例
// 使用方法: go run main.go
// 必要条件: 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"
)

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

// 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はAPI通信を処理します
type CapsolverClient struct {
	APIKey string
	Client *http.Client
}

// NewCapsolverClientは新しいCapSolverクライアントを作成します
func NewCapsolverClient(apiKey string) *CapsolverClient {
	return &CapsolverClient{
		APIKey: apiKey,
		Client: &http.Client{Timeout: 120 * time.Second},
	}
}

// GetBalanceはアカウント残高を取得します
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("残高確認失失敗しました")
	}

	return result.Balance, nil
}

// SolveRecaptchaV2はreCAPTCHA v2チャレンジを解決します
func (c *CapsolverClient) SolveRecaptchaV2(websiteURL, siteKey string) (string, error) {
	log.Printf(" %s のreCAPTCHA v2タスクを作成しています", websiteURL)

	// タスクの作成
	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("タスクの作成に失敗しました: %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("APIエラー: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("タスクを作成しました: %s", createResult.TaskID)

	// 結果のポーリング
	for i := 0; i < 120; i++ {
		result, err := c.getTaskResult(createResult.TaskID)
		if err != nil {
			return "", err
		}

		if result.Status == "ready" {
			log.Printf("CAPTCHAが正常に解決しました!")
			return result.Solution.GRecaptchaResponse, nil
		}

		if result.Status == "failed" {
			return "", fmt.Errorf("タスクが失敗しました: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("解決を待機中... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("解決を待つするタイムアウト")
}

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はページHTMLからreCAPTCHAサイトキーを抽出します
func extractSiteKey(html string) string {
	// 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は解決されたトークンをページに挿入します
func injectRecaptchaToken(page *rod.Page, token string) error {
	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)

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

func main() {
	// APIキーのチェック
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("CAPSOLVER_API_KEY環境変数が必要です")
	}

	// ターゲットURL - GoogleのreCAPTCHAデモページ
	targetURL := "https://www.google.com/recaptcha/api2/demo"

	log.Println("==============================================")
	log.Println("Katana + CapSolver - reCAPTCHA v2デモ")
	log.Println("==============================================")

	// CapSolverクライアントの初期化
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// 残高の確認
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("警告: 残高を確認できませんでした: %v", err)
	} else {
		log.Printf("CapSolver残高: $%.2f", balance)
	}

	// ブラウザの起動
	log.Println("ブラウザを起動しています...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(true).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// ターゲットに移動
	log.Printf("移に移動しています: %s", targetURL)
	page := browser.MustPage(targetURL)
	page.MustWaitLoad()
	time.Sleep(2 * time.Second)

	// ページHTMLを取得し、サイトキーを抽出
	html := page.MustHTML()

	// reCAPTCHAの確認
	if !strings.Contains(html, "g-recaptcha") && !strings.Contains(html, "grecaptcha") {
		log.Fatal("ページにreCAPTCHAが見つかりません")
	}

	log.Println("reCAPTCHAが検出されました!")

	// サイトキーの抽出
	siteKey := extractSiteKey(html)
	if siteKey == "" {
		log.Fatal("サイトキーを抽出できませんでした")
	}
	log.Printf("サイトキー: %s", siteKey)

	// CAPTCHAの解決
	log.Println("CapSolverでCAPTCHAを解決しています...")
	token, err := client.SolveRecaptchaV2(targetURL, siteKey)
	if err != nil {
		log.Fatalf("CAPTCHAの解決に失敗しました: %v", err)
	}

	log.Printf("トークンを取得しました: %s...", token[:50])

	// トークンの挿入
	log.Println("トークンをページに挿入しています...")
	err = injectRecaptchaToken(page, token)
	if err != nil {
		log.Fatalf("トークンの挿入に失敗しました: %v", err)
	}

	// フォームの送信
	log.Println("フォームを送信しています...")
	submitBtn := page.MustElement("#recaptcha-demo-submit")
	submitBtn.MustClick()

	// 結果を
	time.Sleep(3 * time.Second)

	// 結果の確認
	newHTML := page.MustHTML()
	if strings.Contains(newHTML, "Verification Success") || strings.Contains(newHTML, "success") {
		log.Println("==============================================")
		log.Println("成功!reCAPTCHAが解決され、検証されました!")
		log.Println("==============================================")
	} else {
		log.Println("フォームが送信されました - ページを確認してください")
	}

	// ページタイトルを取得
	title := page.MustEval(`document.title`).String()
	log.Printf("最終的なページタイトル: %s", title)
}

設定と実行

bash Copy
# プロジェクトの作成
mkdir katana-recaptcha-v2
cd katana-recaptcha-v2
go mod init katana-recaptcha-v2

# 依存関係のインストール
go get github.com/go-rod/rod@latest

# APIキーの設定
export CAPSOLVER_API_KEY="YOUR_API_KEY"

# 実行
go run main.go

CapSolverでCloudflare Turnstileを解決する方法

Cloudflare Turnstileはプライバシーを重視したCAPTCHAの代替です。以下は完全なスクリプトです:

go Copy
// Cloudflare Turnstile ソルバー - 完全な例
// 使用方法: go run main.go
// 必要条件: 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"
)

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

// 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はAPI通信を処理します
type CapsolverClient struct {
	APIKey string
	Client *http.Client
}

// NewCapsolverClientは新しいCapSolverクライアントを作成します
func NewCapsolverClient(apiKey string) *CapsolverClient {
	return &CapsolverClient{
		APIKey: apiKey,
		Client: &http.Client{Timeout: 120 * time.Second},
	}
}

// GetBalanceはアカウント残高を取得します
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はCloudflare Turnstileチャレンジを解決します
func (c *CapsolverClient) SolveTurnstile(websiteURL, siteKey string) (string, error) {
	log.Printf(" %s のTurnstileタスクを作成しています", websiteURL)

	// タスクの作成
	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("タスクの作成に失敗しました: %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("APIエラー: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("タスクを作成しました: %s", createResult.TaskID)

	// 結果のポーリング
	for i := 0; i < 120; i++ {
		result, err := c.getTaskResult(createResult.TaskID)
		if err != nil {
			return "", err
		}

		if result.Status == "ready" {
			log.Printf("CAPTCHAが正常に解決しました!")
			return result.Solution.Token, nil
		}

		if result.Status == "failed" {
			return "", fmt.Errorf("タスクが失敗しました: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("解決を待機中... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("解決を待機するタイムアウト")
}

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はページHTMLからTurnstileサイトキーを抽出します
func extractSiteKey(html string) string {
	// 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は解決されたトークンをページに挿入します
func injectTurnstileToken(page *rod.Page, token string) error {
	js := fmt.Sprintf(`
		(function() {
			// トークンを設定
			var tokenField = document.querySelector('input[name="cf-turnstile-response"]');
			if (tokenField) {
				tokenField.value = '%s';
			}

			// クリックイベントをトリガー
			var event = new MouseEvent('click');
			tokenField.dispatchEvent(event);

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

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

func main() {
	// APIキーのチェック
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("CAPSOLVER_API_KEY環境変数が必要です")
	}

	// ターゲットURL - Cloudflare Turnstileデモページ
	targetURL := "https://challenges.cloudflare.com/cdn-cgi/challenge-platform/1/14a7978e-603f-48c8-8b05-638c9807396e"

	log.Println("==============================================")
	log.Println("Katana + CapSolver - Cloudflare Turnstile デモ")
	log.Println("==============================================")

	// CapSolverクライアントの初期化
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// 残高の確認
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("警告: 残高を確認できませんでした: %v", err)
	} else {
		log.Printf("CapSolver残高: $%.2f", balance)
	}

	// ブラウザの起動
	log.Println("ブラウザを起動しています...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(true).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// ターゲットに移動
	log.Printf("移動中: %s", targetURL)
	page := browser.MustPage(targetURL)
	page.MustWaitLoad()
	time.Sleep(2 * time.Second)

	// ページHTMLを取得し、サイトキーを抽出
	html := page.MustHTML()

	// Turnstileの確認
	if !strings.Contains(html, "cf-turnstile") {
		log.Fatal("ページにTurnstileが見つかりません")
	}

	log.Println("Turnstileが検出されました!")

	// サイトキーの抽出
	siteKey := extractSiteKey(html)
	if siteKey == "" {
		log.Fatal("サイトキーを抽出できませんでした")
	}
	log.Printf("サイトキー: %s", siteKey)

	// CAPTCHAの解決
	log.Println("CapSolverでCAPTCHAを解決しています...")
	token, err := client.SolveTurnstile(targetURL, siteKey)
	if err != nil {
		log.Fatalf("CAPTCHAの解決に失敗しました: %v", err)
	}

	log.Printf("トークンを取得しました: %s...", token[:50])

	// トークンの挿入
	log.Println("トークンをページに挿入しています...")
	err = injectTurnstileToken(page, token)
	if err != nil {
		log.Fatalf("トークンの挿入に失敗しました: %v", err)
	}

	// フォームの送信
	log.Println("フォームを送信しています...")
	submitBtn := page.MustElement("button[type='submit']")
	submitBtn.MustClick()

	// 結果を待機
	time.Sleep(3 * time.Second)

	// 結果の確認
	newHTML := page.MustHTML()
	if strings.Contains(newHTML, "success") {
		log.Println("==============================================")
		log.Println("成功!Cloudstileが解決され、検証されました!")
		log.Println("==============================================")
	} else {
		log.Println("フォームが送信されました - ページを確認してください")
	}

	// ページタイトルを取得
	title := page.MustEval(`document.title`).String()
	log.Printf("最終的なページタイトル: %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("タスクの作成に失敗しました: %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("APIエラー: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
}

log.Printf("タスクが作成されました: %s", createResult.TaskID)

// 結果をポーリング
for i := 0; i < 120; i++ {
	result, err := c.getTaskResult(createResult.TaskID)
	if err != nil {
		return "", err
	}

	if result.Status == "ready" {
		log.Printf("Turnstileが正常に解決されました!")
		return result.Solution.Token, nil
	}

	if result.Status == "failed" {
		return "", fmt.Errorf("タスクが失敗しました: %s", result.ErrorDescription)
	}

	if i%10 == 0 {
		log.Printf("解決待ち... (%ds)", i)
	}
	time.Sleep(1 * time.Second)
}

return "", fmt.Errorf("解決待ちのタイムアウト")

}

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 はページのHTMLからTurnstileサイトキーを抽出します
func extractTurnstileSiteKey(html string) string {
// パターン1: cf-turnstile divのdata-sitekey属性
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 は解決されたトークンをページに挿入します
func injectTurnstileToken(page *rod.Page, token string) error {
js := fmt.Sprintf(`
(function() {
// cf-turnstile-responseフィールドを設定します
var responseField = document.querySelector('[name="cf-turnstile-response"]');
if (responseField) {
responseField.value = '%s';
}

Copy
		// IDで検索も試みます
		var byId = document.getElementById('cf-turnstile-response');
		if (byId) {
			byId.value = '%s';
		}

		// 必要に応じて隠し入力を作成します
		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);
			}
		}

		// コールバックをトリガーします
		if (window.turnstile && window.turnstileCallback) {
			window.turnstileCallback('%s');
		}

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

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

}

func main() {
// APIキーをチェックします
if CAPSOLVER_API_KEY == "" {
log.Fatal("CAPSOLVER_API_KEY環境変数が必要です")
}

Copy
// ターゲットURL - Cloudflare Turnstileを使用しているサイトに置き換えてください
targetURL := "https://example.com"

log.Println("==============================================")
log.Println("Katana + Capsolver - Turnstileデモ")
log.Println("==============================================")

// Capsolverクライアントを初期化します
client := NewCapsolverClient(CAPSOLVER_API_KEY)

// 残高をチェックします
balance, err := client.GetBalance()
if err != nil {
	log.Printf("警告: 残高をチェックできませんでした: %v", err)
} else {
	log.Printf("Capsolver残高: $%.2f", balance)
}

// ブラウザを起動します
log.Println("ブラウザを起動しています...")
path, _ := launcher.LookPath()
u := launcher.New().Bin(path).Headless(true).MustLaunch()
browser := rod.New().ControlURL(u).MustConnect()
defer browser.MustClose()

// ターゲットにアクセスします
log.Printf("アクセス中: %s", targetURL)
page := browser.MustPage(targetURL)
page.MustWaitLoad()
time.Sleep(2 * time.Second)

// ページHTMLを取得します
html := page.MustHTML()

// Turnstileをチェックします
if !strings.Contains(html, "cf-turnstile") && !strings.Contains(html, "turnstile") {
	log.Println("ページにTurnstileが見つかりません")
	log.Println("ヒント: targetURLをCloudflare Turnstileを使用しているサイトに置き換えてください")
	return
}

log.Println("Cloudflare Turnstileが検出されました!")

// サイトキーを抽出します
siteKey := extractTurnstileSiteKey(html)
if siteKey == "" {
	log.Fatal("サイトキーを抽出できませんでした")
}
log.Printf("サイトキー: %s", siteKey)

// Turnstileを解決します
log.Println("CapsolverでTurnstileを解決しています...")
token, err := client.SolveTurnstile(targetURL, siteKey)
if err != nil {
	log.Fatalf("Turnstileの解決に失敗しました: %v", err)
}

log.Printf("トークンを取得しました: %s...", token[:min(50, len(token))])

// トークンを挿入します
log.Println("トークンをページに挿入しています...")
err = injectTurnstileToken(page, token)
if err != nil {
	log.Fatalf("トークンの挿入に失敗しました: %v", err)
}

log.Println("==============================================")
log.Println("成功!Turnstileトークンが挿入されました!")
log.Println("==============================================")

// ページタイトルを取得します
title := page.MustEval(`document.title`).String()
log.Printf("ページタイトル: %s", title)

}

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

Copy
### Turnstileのポイント

1. **タスクタイプ**: `AntiTurnstileTaskProxyLess` を使用してください
2. **レスポンスフィールド**: Turnstileは `g-recaptcha-response` ではなく `cf-turnstile-response` を使用します
3. **より高速な解決**: Turnstileは通常、reCAPTCHAよりも高速に解決されます (1-10秒)
4. **トークンフィールド**: 解決結果は `solution.token` に含まれます `solution.gRecaptchaResponse` ではありません

---

## 万能CAPTCHAクローラー

すべてのCAPTCHAタイプを自動的に検出および解決する完全なモジュール式クローラーです:

```go
// 万能CAPTCHAクローラー - 完全な例
// reCAPTCHA v2とTurnstileを自動的に検出および解決します
// 使用方法: go run main.go -url "https://example.com"
// 必要条件: 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"
)

// ============================================
// 設定
// ============================================

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

// CaptchaType はさまざまなCAPTCHAタイプを表します
type CaptchaType string

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

// CaptchaInfo は抽出されたCAPTCHAパラメータを含みます
type CaptchaInfo struct {
	Type    CaptchaType
	SiteKey string
}

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

// ============================================
// 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("サポートされていないCAPTCHAタイプ: %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) {
	// タスクを作成します
	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("タスクの作成に失敗しました: %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("APIエラー: %s - %s", createResult.ErrorCode, createResult.ErrorDescription)
	}

	log.Printf("タスクが作成されました: %s", createResult.TaskID)

	// 結果をポーリング
	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("タスクが失敗しました: %s", result.ErrorDescription)
		}

		if i%10 == 0 {
			log.Printf("解決待ち... (%ds)", i)
		}
		time.Sleep(1 * time.Second)
	}

	return "", fmt.Errorf("解決待ちのタイムアウト")
}

// ============================================
// CAPTCHA検出
// ============================================

func DetectCaptcha(html string) *CaptchaInfo {
	// reCAPTCHA v2 (チェックボックス)をチェックします
	if strings.Contains(html, "g-recaptcha") {
		siteKey := extractDataSiteKey(html, "g-recaptcha")
		if siteKey != "" {
			return &CaptchaInfo{
				Type:    RecaptchaV2,
				SiteKey: siteKey,
			}
		}
	}

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

	// 代替パターン
	pattern = fmt.Sprintf(`data-sitekey=['"]([^'"]+)['"][^>]*class=['"][^'"]*%s`, className)
	re = regexp.MustCompile(pattern)
	matches = re.FindStringSubmatch(html)
	if len(matches) > 1 {
		return matches[1]
	}

	// 一般的なサイトキーパターン
	re = regexp.MustCompile(`data-sitekey=['"]([^'"]+)['"]`)
	matches = re.FindStringSubmatch(html)
	if len(matches) > 1 {
		return matches[1]
	}

	return ""
}

// ============================================
// トークン挿入
// ============================================

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("サポートされていないCAPTCHAタイプ: %s", captchaType)
	}

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

// ============================================
// クローラー
// ============================================

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,
成功: false,
	}

	// ターゲットに移動
	log.Printf("ナビゲート中: %s", targetURL)
	page := browser.MustPage(targetURL)
	defer page.MustClose()

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

	// ページHTMLを取得
	html := page.MustHTML()

	// CAPTCHAを検出
	captchaInfo := DetectCaptcha(html)

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

		log.Printf("CAPTCHAを検出: %s (siteKey: %s)", captchaInfo.Type, captchaInfo.SiteKey)

		// CAPTCHAを解決
		log.Println("CapsolverでCAPTCHAを解決中...")
		token, err := client.Solve(captchaInfo, targetURL)
		if err != nil {
			result.Error = fmt.Sprintf("CAPTCHAの解決に失敗: %v", err)
			log.Printf("エラー: %s", result.Error)
			return result
		}

		log.Printf("トークンを受信: %s...", token[:min(50, len(token))])

		// トークンを注入
		log.Println("トークンを注入中...")
		err = InjectToken(page, token, captchaInfo.Type)
		if err != nil {
			result.Error = fmt.Sprintf("トークンの注入に失敗: %v", err)
			log.Printf("エラー: %s", result.Error)
			return result
		}

		result.CaptchaSolved = true
		log.Println("トークンを正常に注入しました!")

		// フォームを送信してみる
		submitForm(page)
		time.Sleep(3 * time.Second)
	} else {
		log.Println("ページにCAPTCHAは検出されませんでした")
	}

	// 最終的なページ情報を取得
	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("送信ボタンをクリック: %s", selector)
			return
		}
	}
}

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

// ============================================
// メイン
// ============================================

func main() {
	// フラグを解析
	targetURL := flag.String("url", "https://www.google.com/recaptcha/api2/demo", "クロールするターゲットURL")
	headless := flag.Bool("headless", true, "ブラウザをヘッドレスモードで実行")
	checkBalance := flag.Bool("balance", false, "アカウント残高のみを確認")
	flag.Parse()

	// APIキーを確認
	if CAPSOLVER_API_KEY == "" {
		log.Fatal("CAPSOLVER_API_KEY環境変数が必要です")
	}

	log.Println("==============================================")
	log.Println("Katana + Capsolver - ウニバーサルCAPTCHAクローラー")
	log.Println("==============================================")

	// クライアントを初期化
	client := NewCapsolverClient(CAPSOLVER_API_KEY)

	// 残高を確認
	balance, err := client.GetBalance()
	if err != nil {
		log.Printf("警告: 残高を確認できませんでした: %v", err)
	} else {
		log.Printf("Capsolver残高: $%.2f", balance)
	}

	if *checkBalance {
		return
	}

	// ブラウザを起動
	log.Println("ブラウザを起動中...")
	path, _ := launcher.LookPath()
	u := launcher.New().Bin(path).Headless(*headless).MustLaunch()
	browser := rod.New().ControlURL(u).MustConnect()
	defer browser.MustClose()

	// クロール
	result := Crawl(browser, client, *targetURL)

	// 結果を出力
	log.Println("==============================================")
	log.Println("クロール結果")
	log.Println("==============================================")
	log.Printf("URL: %s", result.URL)
	log.Printf("タイトル: %s", result.Title)
	log.Printf("成功: %v", result.Success)
	log.Printf("CAPTCHA検出: %v", result.CaptchaFound)
	if result.CaptchaFound {
		log.Printf("CAPTCHAタイプ: %s", result.CaptchaType)
		log.Printf("CAPTCHA解決: %v", result.CaptchaSolved)
	}
	if result.Error != "" {
		log.Printf("エラー: %s", result.Error)
	}
	log.Println("==============================================")
}

使用方法

bash Copy
# プロジェクトを作成
mkdir katana-universal-crawler
cd katana-universal-crawler
go mod init katana-universal-crawler

# 依存関係をインストール
go get github.com/go-rod/rod@latest

# APIキーを設定
export CAPSOLVER_API_KEY="YOUR_API_KEY"

# デフォルトで実行 (reCAPTCHA v2デモ)
go run main.go

# カスタムURLで実行
go run main.go -url "https://example.com"

# 残高のみ確認
go run main.go -balance

# ヘッドレスモードなしで実行
go run main.go -headless=false

最適な実践方法

1. パフォーマンス最適化

  • ProxyLessタスクタイプを使用する: ReCaptchaV2TaskProxyLessはCapsolverの内部プロキシを使用して高速に解決します
  • 並列処理: 他のページ要素が読み込まれている間にCAPTCHAの解決を開始します
  • トークンキャッシュ: reCAPTCHAトークンは約2分間有効です。可能であればキャッシュを活用してください

2. コスト管理

  • 解決前に検出: CAPTCHAが実際に存在する場合にのみCapsolverを呼び出してください
  • サイトキーの検証: API呼び出し前に抽出されたキーが有効か確認してください
  • 使用状況の監視: コストを効果的に管理するためにAPI呼び出しを追跡してください

3. エラー処理

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("試行 %d に失敗: %v", i+1, err)

        // 指数バックオフ
        time.Sleep(time.Duration(i+1) * time.Second)
    }

    return "", fmt.Errorf("試行回数上限に達しました: %w", lastErr)
}

4. レートリミット

リクエストの間に適切な遅延を実装して検出を回避してください:

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

問題解決

一般的なエラー

エラー 原因 解決策
ERROR_ZERO_BALANCE クレジット不足 Capsolverアカウントに残高を追加してください
ERROR_CAPTCHA_UNSOLVABLE 無効なサイトキー 抽出ロジックを確認してください
ERROR_INVALID_TASK_DATA 必要パラメータが不足 タスク構造体を確認してください
context deadline exceeded タイムアウト タイムアウトを増やしてみてください、またはネットワークを確認してください

デバッグのヒント

  1. ヘッドレスモードを無効化: Headless(false)を設定して何が起きているか確認してください
  2. ネットワークトラフィックをログ: リクエストを監視して問題を特定してください
  3. スクリーンショットを保存: デバッグ用にページ状態をキャプチャしてください
  4. トークンを検証: 注入前にトークンの形式をログに出力してください

よくある質問

Q: CAPTCHAページでヘッドレスモードなしでKatanaを使用できますか?
A: いいえ、CAPTCHAページではJavaScriptのレンダリングが必要であり、ヘッドレスモードでのみ動作します。

Q: CAPTCHAトークンはどれくらい有効ですか?
A: reCAPTCHAトークン: 約2分。Turnstile: 設定により異なります。

Q: 平均的な解決時間はどのくらいですか?
A: reCAPTCHA v2: 5-15秒、Turnstile: 1-10秒。

Q: 自前のプロキシを使用できますか?
A: はい、"ProxyLess"の接尾辞を持たないタスクタイプを使用し、プロキシ設定を提供してください。


結論

CapsolverをKatanaと統合することで、ウェブクローリングのための信頼性の高いCAPTCHA処理が可能になります。上記の完全なスクリプトは直接コピーしてGoプロジェクトで使用できます。

準備はできましたか? Capsolverに登録 そしてクローラーを強化してください!

💡 Katana統合ユーザー向け特典:
この統合を記念して、このチュートリアルを通じて登録したCapsolverユーザーに6%のボーナスコードを提供しています — Katana。ダッシュボードで再充電時にコードを入力すると、即座に追加の6%クレジットが得られます。


12. ドキュメンテーション

コンプライアンス免責事項: このブログで提供される情報は、情報提供のみを目的としています。CapSolverは、すべての適用される法律および規制の遵守に努めています。CapSolverネットワークの不法、詐欺、または悪用の目的での使用は厳格に禁止され、調査されます。私たちのキャプチャ解決ソリューションは、公共データのクローリング中にキャプチャの問題を解決する際に100%のコンプライアンスを確保しながら、ユーザーエクスペリエンスを向上させます。私たちは、サービスの責任ある使用を奨励します。詳細については、サービス利用規約およびプライバシーポリシーをご覧ください。

もっと見る

Pythonでウェブサイトをクローリングする際の403 Forbiddenエラーの解決方法
Pythonでウェブサイトをクロールする際の403エラーの解決方法

Pythonでウェブサイトをクロールする際の403 Forbiddenエラーを乗り越える方法を学びましょう。このガイドでは、IPローテーション、User-Agentのスプーフィング、リクエストのスローティング、認証処理、アクセス制限を回避し、ウェブスキャッピングを成功裏に継続するためのヘッドレスブラウザの使用についてカバーしています。

web scraping
Logo of CapSolver

Sora Fujimoto

13-Jan-2026

アグノとカプソルバーの統合
アグノでキャプソルバー統合を使用してCaptchaを解く方法

自律型AIエージェントでreCAPTCHA v2/v3、Cloudflare Turnstile、WAFのチャレンジを解決する方法を学びましょう。ウェブスクラビングと自動化のための実際のPythonコード例を含みます。

web scraping
Logo of CapSolver

Sora Fujimoto

13-Jan-2026

Katanaを使ってCAPTCHAを解く方法 – CapSolverを使用して
カタナとキャップソルバーの統合: ウェブクローリング用の自動CAPTCHA解決

KatanaとCapsolverを統合して、ヘッドレスクローリングでreCAPTCHA v2とCloudflare Turnstileを自動で解決する方法を学ぶ。

Logo of CapSolver

Sora Fujimoto

12-Jan-2026

トップ Python ウェブスクレイピング ライブラリ 2026年
トップ Python ウェブスクラピング ライブラリ 2026年

2026年の最高のPythonウェブスクレイピングライブラリを探索し、特徴、使いやすさ、パフォーマンスを比較して、データ抽出のニーズに応じた情報を提供します。エキスパートの洞察とよくある質問も含まれます。

web scraping
Logo of CapSolver

Adélia Cruz

12-Jan-2026

Crawlabを使用してCapSolverでCaptchaを解く方法
CrawlabとCapSolverの統合: 分散クローリングのための自動CAPTCHA解決

CapSolverをCrawlabに統合して、大規模にreCAPTCHAとCloudflare Turnstileを解決する方法を学びます

web scraping
Logo of CapSolver

Sora Fujimoto

09-Jan-2026

2026年に知っておくべき最高のAIスクラビングツール
2026年に知っておくべき最適なAIスクラッピングツール

2026年の最高のAIスクラピングツールのオプションをチェックしてください。私たちが比較する最高のAIウェブスクラピングツールには、Bright Data、Crawl4AI、Browse AIが含まれており、具体的な価格を提供して、自動データ抽出とセキュリティチャレンジの解決をマスターするお手伝いをします。

web scraping
Logo of CapSolver

Lucas Mitchell

07-Jan-2026