Scarnox · Blog

Goでcaptcha解決:net/httpを使った動作例(2026年)

Goでcaptchaソルバーを作るのに、サードパーティ製のパッケージは不要です。標準ライブラリのnet/httpとencoding/jsonで、流れ全体をまかなえます。Scarnox APIへのPOSTが1回、JSONのレスポンスが1回、そしてサイトのフォームへの送信が1回です。このガイドでは、Scarnoxが現在プロキシなしで解決しているPopularCaptchaについて、この流れを実装します。

無料のトライアルクレジットで始める(カード登録は不要)と、他で使う前に、自分が管理しているページに対してプログラムを実行できます。

必要なもの

完全なプログラム

この1つのファイルで、captchaを解決し、一時的な失敗を再試行し、トークンをフォームに送信します。main.goとして保存してください。

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"time"
)

const apiURL = "https://api.scarnox.com/api/tasks/create"

// 解決呼び出しはトークンが準備できるまで待つため、タイムアウトは長めにしている。
var apiClient = &http.Client{Timeout: 185 * time.Second}

type createRequest struct {
	CaptchaType string `json:"captcha_type"`
	SiteKey     string `json:"site_key"`
	SiteURL     string `json:"site_url"`
	IsInvisible bool   `json:"is_invisible,omitempty"`
}

type createResponse struct {
	ErrorID          int    `json:"errorId"`
	ErrorCode        string `json:"errorCode"`
	ErrorDescription string `json:"errorDescription"`
	Solution         struct {
		Token string `json:"token"`
	} `json:"solution"`
}

func solveCaptcha(apiKey, sitekey, pageURL string, invisible bool) (string, error) {
	body, err := json.Marshal(createRequest{
		CaptchaType: "PopularCaptchaTaskProxyless",
		SiteKey:     sitekey,
		SiteURL:     pageURL,
		IsInvisible: invisible,
	})
	if err != nil {
		return "", err
	}

	req, err := http.NewRequest(http.MethodPost, apiURL, bytes.NewReader(body))
	if err != nil {
		return "", err
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := apiClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	raw, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var out createResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return "", fmt.Errorf("HTTP %d, response was not JSON: %s", resp.StatusCode, raw)
	}
	if out.ErrorID != 0 {
		return "", fmt.Errorf("%s: %s", out.ErrorCode, out.ErrorDescription)
	}
	return out.Solution.Token, nil
}

// solveWithRetryは一時的な失敗を再試行する。失敗した解決は課金されない。
func solveWithRetry(apiKey, sitekey, pageURL string, attempts int) (string, error) {
	var lastErr error
	for i := 1; i <= attempts; i++ {
		token, err := solveCaptcha(apiKey, sitekey, pageURL, false)
		if err == nil {
			return token, nil
		}
		lastErr = err
		log.Printf("attempt %d failed: %v", i, err)
		time.Sleep(time.Duration(i) * time.Second)
	}
	return "", lastErr
}

func main() {
	apiKey := os.Getenv("SCARNOX_API_KEY")
	if apiKey == "" {
		log.Fatal("set SCARNOX_API_KEY")
	}

	const pageURL = "https://example.com/signup"
	const sitekey = "YOUR-SITEKEY-UUID"

	token, err := solveWithRetry(apiKey, sitekey, pageURL, 3)
	if err != nil {
		log.Fatal(err)
	}

	// Cookieジャーは、captchaをサイトのセッションに結びつけておくためのもの。
	jar, err := cookiejar.New(nil)
	if err != nil {
		log.Fatal(err)
	}
	site := &http.Client{Jar: jar, Timeout: 60 * time.Second}

	form := url.Values{}
	form.Set("email", "you@example.com")
	form.Set("h-captcha-response", token)
	form.Set("g-recaptcha-response", token)

	resp, err := site.PostForm(pageURL, form)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	fmt.Println("Status:", resp.Status)
}

実行します。

export SCARNOX_API_KEY=scarnox_YOURAPIKEY
go run main.go

各部分の役割

リクエスト。 solveCaptchaは、APIが期待するJSONボディに構造体をマーシャルし、Authorizationヘッダーを設定します。Bearerの接頭辞は必須です。

タイムアウト。 APIはトークンの準備ができるまでブロックするので、クライアントのタイムアウトは185秒です。これより短くすると、もうすぐ完了する解決をキャンセルしてしまいます。

エラーのチェック。 APIは成功時にerrorIdを0で返します。それ以外の値の場合はerrorCodeとerrorDescriptionが付き、関数はそれをエラーとして返します。トークンはsolution.tokenにあります。

送信。 トークンはh-captcha-responseフィールドに入り、g-recaptcha-responseにも同じ値が入ります。サイトはどちらか一方を読むことが多いためです。

多くの会員登録や検索のページは、captchaをセッションに紐づけています。サイトのクライアントに設定したcookiejarは、フォームを表示するGETと、それを送信するPOSTの間でCookieを保持します。これを省くと、本来は有効なトークンでも、サイトに拒否されることがあります。

タイミング

トークンは約2分で期限切れになるので、送信の直前に解決してください。長い処理の開始時に解決して、そのまま待つのはやめてください。猶予をどう計算するかは、captchaトークンの期限切れで説明しています。

不可視のウィジェット

ページのウィジェットが不可視の場合は、invisible引数をtrueにしてください。リクエストにはis_invisible: trueが含まれます。ページによっては、トークンとともに呼び出すJavaScriptのコールバックも必要です。スクリプトを確認して見つけてください。パターンは不可視captchaのガイドにまとめています。

同時実行

Goではgoroutineを使えば、多くのcaptchaを同時に解決するのは簡単です。同時解決数は、アカウントと対象サイトが扱える範囲に抑えてください。ソルバーが追いつけるとしても、1つのドメインに一度に大量のリクエストを送るべきではありません。サイトのrobots.txtと利用規約を尊重し、収集するのは許可された公開データに限ってください。

料金

Scarnoxは成功した解決ごとに課金します。失敗した解決は無料です。料金の詳細は料金ページを参照してください。APIを試すには、無料のトライアルクレジットで始める(カード登録は不要)ことができます。

次のステップ