Scarnox · Blog

Node.jsでcaptcha解決:fetchを使った動作例(2026年)

Node.jsでcaptchaソルバーを作るのは、HTTPリクエストが1回です。Node 18以降にはfetchが含まれているので、APIを呼び出すのにパッケージは不要です。サイトキーとページURLを送り、レスポンスを待ち、トークンをフォームに入れてください。このガイドでは、Scarnoxが現在プロキシなしで解決しているPopularCaptchaの流れ全体を示します。

まず下のコードをテスト用のページで実行してください。無料のトライアルクレジットで始める(カード登録は不要)こともできます。

必要なもの

ソルバーモジュール

以下のモジュールは1つの関数です。Bearerヘッダーを付けてAPIにPOSTし、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以外になり、その分の課金はされません。一時的な失敗には短いリトライループで十分です。試行回数は少なく保ち、サイトキーやページ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;
}

より完全なエラーのポリシーは、captcha解決のエラー処理を参照してください。

トークンの送信

トークンは、サイトが期待するフォームのフィールドに入れます。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

CookieとセッションCookie

素のfetchは、リクエストの間でCookieを保持しません。多くの会員登録や検索のページは、captchaをセッションCookieに紐づけているため、対応するCookieなしで送ったトークンは拒否されることがあります。扱い方は2つあります。

フォームが単純で、サイトがJavaScriptをあまり実行しない場合は前者を選びます。それ以外は後者を選んでください。

実用的な確認方法として、POSTの後にステータスコードと最終的なURLを見てください。成功ページへのリダイレクトは、通常、トークンが受け付けられたことを意味します。ウィジェットがもう一度表示されるページは、通常、拒否されたか、GETのCookieが引き継がれていないことを意味します。最初の数回の実行ではレスポンスのボディをログに残して、どちらの場合かを見分けてください。

タイミング

トークンは約2分で期限切れになります。送信の直前に解決してください。よくある間違いは、長い処理の開始時に解決し、後で送信することです。解決したら、すぐに送信してください。captchaトークンの期限切れで詳しく扱っています。

不可視のcaptcha

ページのウィジェットがdata-size="invisible"を持つ場合は、{ invisible: true }を渡してください。関数はリクエストにis_invisible: trueを付けて送ります。

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

ページがウィジェットにコールバックを付けている場合、フォームはトークンを引数にそのコールバックを呼ぶ必要があるかもしれません。ページのスクリプトを読んで見つけてください。パターンは不可視captchaのガイドで扱っています。

ソルバーでのスクレイピング

captchaが、送信するフォームではなく、スクレイピングするページに出てくることもあります。同じパターンが使えます。HTMLの中のウィジェットを検出し、解決して、ウィジェットがPOSTする先のURLに送信します。リクエストの頻度は低く保ち、送信前にサイトの利用規約を確認してください。責任あるスクレイピングとして、robots.txtを尊重し、必要のない個人データは避け、サーバーに負荷をかけないでください。

料金

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

次のステップ