Scarnox · Blog

Node.js로 만드는 캡차 솔버: fetch를 이용한 실전 예제 (2026)

Node.js에서 캡차 솔버는 HTTP 요청 한 번입니다. Node 18 이상에는 fetch가 내장되어 있으므로 API를 호출하는 데 패키지가 필요 없습니다. sitekey와 페이지 URL을 보내고, 응답을 기다린 뒤, 토큰을 폼에 넣으면 됩니다. 이 가이드는 Scarnox가 현재 프록시 없이 풀 수 있는 PopularCaptcha의 전체 흐름을 보여 줍니다.

무료 체험 크레딧으로 시작하세요. 카드 등록은 필요 없습니다. 아래 코드는 먼저 테스트 페이지에서 실행해 보세요.

요구 사항

솔버 모듈

아래 모듈은 함수 하나입니다. Bearer 헤더와 함께 API에 요청하고, 185초 후 중단하며, errorId가 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), // 토큰이 준비되면 호출이 반환됩니다
  });

  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;
}

폴링은 없습니다. 토큰이 준비될 때까지 요청이 열려 있으며, 성공하면 토큰은 solution.token에 있습니다.

재시도

실패한 풀이는 errorId가 0이 아닌 값을 반환하며, 이에 대해서는 요금이 청구되지 않습니다. 일시적인 실패에는 짧은 재시도 루프면 충분합니다. 잘못된 sitekey나 페이지 URL 때문에 시간이 낭비되지 않도록 시도 횟수는 적게 유지하세요.

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;
}

더 완전한 오류 정책은 캡차 솔버 오류 처리를 참고하세요.

토큰 제출하기

토큰은 사이트가 기대하는 폼 필드에 넣습니다. 대부분의 PopularCaptcha 페이지는 h-captcha-response를 읽고, 많은 페이지가 g-recaptcha-response도 읽습니다. 안전하게 둘 다 보내세요.

// 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);

실행하세요.

SCARNOX_API_KEY=scarnox_YOURAPIKEY node submit.mjs

쿠키와 세션

기본 fetch는 요청 사이에 쿠키를 유지하지 않습니다. 많은 회원가입과 검색 페이지가 캡차를 세션 쿠키에 묶어 두므로, 일치하는 쿠키 없이 보낸 토큰은 거부될 수 있습니다. 처리 방법은 두 가지입니다.

폼이 단순하고 사이트가 JavaScript를 많이 실행하지 않는다면 첫 번째 방법을, 그 밖의 복잡한 경우에는 두 번째 방법을 고르세요.

확인할 만한 방법도 있습니다. POST 후 상태 코드와 최종 URL을 살펴보세요. 성공 페이지로의 리다이렉트는 보통 토큰이 받아들여졌다는 뜻입니다. 위젯이 다시 표시되는 페이지는 보통 거부되었거나, GET의 쿠키가 함께 전달되지 않았다는 뜻입니다. 처음 몇 번의 실행에서는 응답 본문을 기록해 어느 경우인지 확인하세요.

타이밍

토큰은 약 2분 뒤에 만료됩니다. 제출 시점에 가깝게 풀이하세요. 흔한 실수는 긴 작업의 시작에서 풀어 놓고 나중에 제출하는 것입니다. 풀이한 뒤 바로 제출하세요. 자세한 내용은 캡차 토큰 만료에서 다룹니다.

비가시형 캡차

페이지의 위젯에 data-size="invisible"이 있다면 { invisible: true }를 전달하세요. 그러면 함수가 요청과 함께 is_invisible: true를 보냅니다.

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

페이지가 위젯에 콜백을 연결해 두었다면, 토큰과 함께 그 함수를 호출해야 할 수도 있습니다. 페이지 스크립트를 읽어 찾으세요. 패턴은 비가시형 캡차 가이드에서 다룹니다.

솔버와 함께 스크래핑하기

때로는 캡차가 제출하는 폼이 아니라, 스크래핑하는 페이지에 나타납니다. 같은 패턴이 적용됩니다. HTML에서 위젯을 찾고, 풀고, 위젯이 토큰을 보내는 URL에 제출하세요. 요청 속도는 낮게 유지하고, 먼저 사이트 약관을 확인하세요. 책임감 있게 스크래핑하세요. robots.txt를 존중하고, 필요 없는 개인 데이터는 피하고, 서버를 몰아붙이지 마세요.

요금

Scarnox는 성공한 풀이 건당 과금합니다. 실패한 풀이는 청구되지 않습니다. 현재 요금은 요금 페이지를 참고하세요. 시작하려면 무료 체험 크레딧으로 시작하세요. 카드 등록은 필요 없습니다.

다음 단계