Scarnox · Blog

Bộ giải captcha bằng Node.js: ví dụ hoạt động với fetch (2026)

Một bộ giải captcha trong Node.js chỉ là một yêu cầu HTTP. Node 18 trở lên đi kèm fetch, nên bạn không cần gói nào để gọi API. Gửi sitekey và URL trang, chờ phản hồi, và đặt token vào form. Hướng dẫn này trình bày toàn bộ 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 mã bên dưới trên một trang thử nghiệm trước.

Yêu cầu

Module bộ giải

Module dưới đây là một hàm duy nhất. Nó gửi yêu cầu đến API với header Bearer, hủy sau 185 giây, và ném lỗi khi errorId khác 0:

// solver.mjs
const API_URL = "https://api.scarnox.com/api/tasks/create";

export async function solveCaptcha(sitekey, pageUrl, { invisible = false } = {}) {
  const body = {
    captcha_type: "PopularCaptchaTaskProxyless",
    site_key: sitekey,
    site_url: pageUrl,
  };
  if (invisible) body.is_invisible = true;

  const res = await fetch(API_URL, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SCARNOX_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(185_000), // lời gọi trả về khi token đã sẵn sàng
  });

  const data = await res.json().catch(() => null);
  if (!data) throw new Error(`HTTP ${res.status}: response was not JSON`);

  if (data.errorId !== 0) {
    throw new Error(`${data.errorCode}: ${data.errorDescription}`);
  }
  return data.solution.token;
}

Không có polling. Yêu cầu vẫn mở cho đến khi token sẵn sàng, và khi thành công, token nằm trong solution.token.

Thử lại

Một lần giải thất bại trả về errorId khác 0, và bạn không bị tính phí cho nó. Một vòng lặp thử lại ngắn là đủ cho các lỗi tạm thời. Giữ số lần thử thấp, để một sitekey hoặc URL trang sai không làm tốn thời gian:

export async function solveWithRetry(sitekey, pageUrl, attempts = 3) {
  let lastError;
  for (let i = 1; i <= attempts; i++) {
    try {
      return await solveCaptcha(sitekey, pageUrl);
    } catch (err) {
      lastError = err;
      console.warn(`Attempt ${i} failed: ${err.message}`);
      await new Promise((r) => setTimeout(r, 1000 * i));
    }
  }
  throw lastError;
}

Để có chính sách lỗi đầy đủ hơn, xem xử lý lỗi bộ giải captcha.

Gửi token

Token được đưa vào trường form mà website mong đợi. Hầu hết trang PopularCaptcha đọc h-captcha-response, và nhiều trang cũng đọc g-recaptcha-response. Hãy gửi cả hai cho an toàn:

// submit.mjs
import { solveWithRetry } from "./solver.mjs";

const pageUrl = "https://example.com/signup";
const token = await solveWithRetry("YOUR-SITEKEY-UUID", pageUrl);

const form = new URLSearchParams({
  email: "you@example.com",
  "h-captcha-response": token,
  "g-recaptcha-response": token,
});

const res = await fetch(pageUrl, {
  method: "POST",
  body: form,
  redirect: "manual",
});
console.log("Status:", res.status);

Chạy nó với:

SCARNOX_API_KEY=scarnox_YOURAPIKEY node submit.mjs

fetch thuần không giữ cookie giữa các yêu cầu. Nhiều trang đăng ký và tìm kiếm gắn captcha với cookie phiên, nên một token gửi đi mà không có cookie khớp có thể bị từ chối. Có hai cách để xử lý:

Chọn cách đầu khi form đơn giản và website không chạy nhiều JavaScript. Chọn cách thứ hai cho mọi thứ phức tạp hơn.

Một cách kiểm tra thực tế: sau POST, hãy xem mã trạng thái và URL cuối cùng. Chuyển hướng đến trang thành công thường có nghĩa là token được chấp nhận. Một trang hiển thị lại widget thường có nghĩa là token bị từ chối, hoặc cookie từ GET không đi theo. Ghi log nội dung phản hồi trong vài lần chạy đầu để bạn biết mình đang ở trường hợp nào.

Thời gian

Token hết hạn trong khoảng hai phút. Hãy giải gần thời điểm bạn submit. Lỗi thường gặp là giải ở đầu một công việc dài rồi submit sau đó. Hãy giải, rồi submit ngay. Hết hạn token captcha trình bày chi tiết hơn.

Captcha ẩn

Nếu widget của trang có data-size="invisible", hãy truyền { invisible: true }. Khi đó hàm gửi is_invisible: true cùng yêu cầu:

const token = await solveCaptcha("YOUR-SITEKEY-UUID", pageUrl, { invisible: true });

Nếu trang cũng gắn một callback vào widget, form có thể cần gọi hàm đó với token. Đọc script của trang để tìm nó. Hướng dẫn captcha ẩn trình bày các mẫu thường gặp.

Scraping cùng bộ giải

Đôi khi captcha xuất hiện trên một trang bạn scrape thay vì một form bạn submit. Mẫu tương tự vẫn áp dụng: phát hiện widget trong HTML, giải nó, rồi gửi nó đến URL mà widget đăng lên. Giữ tốc độ yêu cầu thấp và kiểm tra điều khoản của website trước. Thu thập dữ liệu có trách nhiệm: tôn trọng robots.txt, tránh dữ liệu cá nhân không cần thiết, và đừng làm quá tải máy chủ.

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í. Để biết mức phí hiện tại, xem trang bảng giá. Để bắt đầu, bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ.

Các bước tiếp theo