Bộ giải captcha bằng Go: ví dụ hoạt động với net/http (2026)
Một bộ giải captcha bằng Go không cần gói bên thứ ba nào. net/http và encoding/json của thư viện chuẩn bao quát toàn bộ luồng: một lệnh POST đến API của Scarnox, một phản hồi JSON, và một lần submit form đến website. Hướng dẫn này xây dựng luồng đó cho PopularCaptcha, loại mà Scarnox giải hôm nay theo kiểu proxyless.
Bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ và chạy chương trình trên một trang bạn kiểm soát trước khi dùng nó ở nơi khác.
Yêu cầu
- Go 1.21 trở lên.
- Một khóa API của Scarnox, đọc từ biến môi trường.
- Sitekey của widget PopularCaptcha trên trang. Nếu bạn cần trợ giúp tìm nó, xem cách tìm sitekey của captcha.
Chương trình đầy đủ
Tệp đơn này giải captcha, thử lại các lỗi tạm thời và submit token vào form. Lưu nó thành 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"
// Lời gọi giải bị chặn cho đến khi token sẵn sàng, nên timeout dài.
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 thử lại các lỗi tạm thời. Các lần giải thất bại không bị tính phí.
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 jar giữ phiên mà website gắn captcha với.
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)
}
Chạy nó:
export SCARNOX_API_KEY=scarnox_YOURAPIKEY
go run main.go
Các phần hoạt động cùng nhau thế nào
Yêu cầu. solveCaptcha marshal một struct thành thân JSON mà API mong đợi và đặt header Authorization. Tiền tố Bearer là bắt buộc.
Timeout. API bị chặn cho đến khi token sẵn sàng, nên timeout phía client là 185 giây. Đừng đặt thấp hơn, nếu không bạn sẽ hủy những lần giải lẽ ra đã gần xong.
Kiểm tra lỗi. API trả về errorId là 0 khi thành công. Mọi giá trị khác đi kèm errorCode và errorDescription, và hàm trả về chúng dưới dạng lỗi. Token nằm tại solution.token.
Submit. Token được đưa vào trường h-captcha-response, và g-recaptcha-response nhận cùng giá trị. Hầu hết website đọc một trong hai.
Dùng cookie jar
Nhiều trang đăng ký và tìm kiếm gắn captcha với phiên. cookiejar trên site client giữ các cookie đó giữa GET hiển thị form và POST submit nó. Nếu bỏ qua nó, website có thể từ chối một token vốn hợp lệ.
Thời gian
Token hết hạn trong khoảng hai phút, nên hãy giải ngay trước khi submit. Đừng giải ở đầu một công việc dài rồi chờ. Hết hạn token captcha giải thích cách xác định khoảng thời gian.
Widget ẩn
Nếu widget trên trang là ẩn, hãy đặt đối số invisible thành true. Khi đó yêu cầu có is_invisible: true. Một số trang cũng cần một hàm callback được gọi với token. Kiểm tra script của trang để tìm nó. Hướng dẫn captcha ẩn liệt kê các mẫu thường gặp.
Đồng thời
Go giúp dễ dàng giải nhiều captcha cùng lúc bằng goroutine. Giữ số lần giải đồng thời trong khả năng chịu đựng của tài khoản và website mục tiêu. Một tên miền không nên nhận một đợt yêu cầu bùng nổ, ngay cả khi bộ giải của bạn có thể theo kịp. Tôn trọng robots.txt và điều khoản của website, và giới hạn việc scraping ở dữ liệu công khai mà bạn được phép thu thập.
Giá
Scarnox tính phí theo mỗi lần giải thành công. Các lần giải thất bại không bị tính phí. Xem bảng giá hiện tại để biết mức phí. Để thử API, bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ.