
Sora Fujimoto
AI Solutions Architect

ReCaptchaV2TaskProxyLess、websiteURL、websiteKeyを使用し、準備が整うとgRecaptchaResponseを返す。needs_review状態によって、ループや誤った在庫アラートを防ぐ。小売ページが場所によって動作を変更したり、ストアセレクターを必要としたり、認証されたブラウザセッションをCAPTCHAで一時停止したりする場合、在庫データの収集は単純に見えるが、実際は複雑になる。信頼できる収集者は、製品とストアのコンテキストを保持し、同じセッションでチェックポイントを解決し、ページが実際の在庫状態を返したことを証明する必要がある。CapSolverは、この制御された復元ステップ内のCAPTCHAインフラストラクチャとして機能することができる。
このガイドは、承認された補充計画、商品管理の品質保証、または顧客向け在庫通知のための公開製品の可用性をモニタリングする具体的な小売運用シナリオに焦点を当てている。成功したCAPTCHAタスクが在庫要求の成功を意味するとは仮定していない。ターゲットアプリケーションが認識された在庫結果を提供し、収集者が「在庫切れ」と「不明」を区別する十分な証拠を記録した場合にのみ、ワークフローは終了する。
小売在庫データ収集は、下流システムが信頼できる小さな安定したレコードを返すべきである。有用なレコードには、小売業者、コア製品識別子、要求されたストアまたは郵便エリア、観測された可用性、収集時間、証拠のソースが含まれる。価格は含まれる場合もあるが、明示的な在庫状態に置き換えてはならない。
{
"retailer": "authorized-demo-store",
"product_id": "SKU-4821",
"store_id": "STORE-017",
"postal_area": "10001",
"availability": "in_stock",
"quantity_hint": "limited",
"observed_at": "2026-08-13T09:15:00Z",
"source": "product-page",
"verification": "inventory-label-and-store-id",
"captcha_recovery": "completed"
}
入力は、製品URLに加えて許可されたストアコンテキストである。操作は、場所を選択または確認し、検証チェックポイントを検出、認証された場合に解決し、在庫状態を読み取り、結果を正規化する。出力は上記のレコードまたは終端状態(not_found、out_of_stock、needs_review、policy_deniedなど)である。タイムアウト、チャレンジループ、ログインウォール、不正な応答をout_of_stockに変換してはならない。この誤りは偽のビジネスシグナルを生成する。
CapSolver CAPTCHA解決FAQはサービスの境界を説明し、ブラウザ自動化ガイドはページ状態を維持するための広範な文脈を提供する。このユーザーケースでは、ブラウザがナビゲーションと証拠を所有し、CapSolverが文書化されたCAPTCHAタスクを所有し、アプリケーションが認証、リトライポリシー、最終的な検証を所有する。
小売収集者は、在庫が表示される前にいくつかの状態を保持するアクションを通常行う。製品ページを読み込み、地域設定を受け入れ、ストアを選択し、ピックアップパネルを開き、ページによって開始された公開在庫エンドポイントを呼び出すなど。CAPTCHAは最初のページがレンダリングされる前に、またはそのアクションの後に表示されることがある。収集者がそれを一般的なHTMLとして扱うと、セレクターが失敗し、ジョブが空または誤ったレコードを書き込む可能性がある。
正しい対応は、盲目的なリトライではなく状態遷移である。収集者はcollectingからcaptcha_requiredに移行し、現在の製品と場所のコンテキストを凍結し、文書化されたチャレンジフィールドのみを収集し、プロバイダーのアダプターを呼び出す。準備が整ったプロバイダーの応答はワークフローをapply_solutionに移動させ、アプリケーションの受け入れはverify_inventoryに移動させる。拒否された結果、繰り返しのチェックポイント、予期しないホスト、または期限切れはneeds_reviewに移動させる。
この設計により、3つの異なる真実が分離される:
3番目の真実のみが、ジョブが在庫レコードを公開できる。この分離は、小売業者がキャッシュされたコンテンツを使用し、地域ドメイン間でリダイレクトし、初期HTMLの読み込み後に在庫を非同期に更新する場合に特に重要である。
6つの責任範囲が狭いコンポーネントを使用する。
スコープレジストリは、承認されたホスト名、収集目的、製品パス、ストア地域、スケジュール、連絡先の所有者をリストアップする。また、除外項目を記録する必要がある:認証されたアカウント領域、従業員ポータル、チェックアウト、支払い、個人プロフィール、およびサイトオーナーまたは契約によってスコープ外とされるパス。レジストリに一致しない要求は、ブラウザが開く前に停止する。
ブラウザはロケール、ストア選択、クッキー、ナビゲーション状態を確立する。1つのブラウザコンテキスト内で1つの製品チェックを保持する。異なるストア間で関係のないクッキーを再利用すると、場所のずれが発生する可能性がある。CAPTCHA復元中にコンテキストを破棄すると、解決策が無効になる。ジョブに必要な最小限のデータのみを保持し、保持ポリシーに従ってクリアする。
検出器は、明示的なウィジェット要素、既知の応答フィールド、チャレンジスクリプト、または検証ルートを検索する。CAPTCHAと通常の問題(404、同意ダイアログ、利用不可のストア、アプリケーションエラーなど)を区別する。CapSolver用語集は、ログとランブックでチャレンジ用語の一貫性を保つために役立つ。
アダプターは、チャレンジタイプ、ページURL、サイトキー、相関IDを含む狭い要求を受け取る。シークレットストレージからAPIキーを読み込み、1つのタスクを作成し、期限内に同じタスクをポーリングし、結果のスキーマを検証し、正規化された成功または失敗を返す。どのサイトが許可されているかを決定したり、在庫データを書き込んだりしない。
抽出器は、ページまたは公開応答を安定した在庫スキーマにマッピングする。バグの多いビジュアル位置よりも、耐久性のある製品識別子、ストアID、構造化データ、明示的な利用可能性テキストを優先する。ページに複数の履行モードが含まれている場合、ピックアップ、配送、ローカル配送を1つのブール値に統合するのではなく、別々に記録する。
証拠レイヤーは、非機密の診断事実を保存する:相関ID、許可されたホスト名、製品ID、ストアID、チャレンジタイプ、プロバイダーのタスクID、経過時間、最終状態、検証に使用されたセレクターまたは応答フィールド。トークン、クッキー、APIキー、住所、顧客データをマスキングする。意味のある状態変化のみをアラートし、一時的な結果が運用ノイズを引き起こす可能性がある場合は、2回の観測を必要とする。
CAPTCHA復元を実装する前に、選択した小売ページを自動化する権限があることを確認し、収集目的が文書化されていることを確認する。契約上の制限、適用可能な法律、あなたの使用に該当するロボットの指示、および適切なリクエストレートを尊重する。ロボット排除プロトコルは、標準化されたクローラーの指示を記述しているが、これは広範な承認レビューの一信号であり、アクセスの許可ではない。
以下の前提条件を使用する:
requestsおよびPlaywrightがインストールされている。シークレットは、管理された環境またはシークレットストアから取得する。OWASPシークレット管理ガイドは、資格情報、アプリケーションコード、ログ、ビルドアーティファクトから分離することをサポートする。実際のクライアントキー、クッキー、解決トークン、または顧客住所を記事、プロンプト、スクリーンショット、トラブルシューティングチケットに配置しないでください。
検出器は、検証ページをトリガーするすべてのアクションの後に実行されるべきである:初期ナビゲーション、ストア変更、ピックアップパネルの開閉、ページネーション、在庫のリフレッシュ。検出は単純なブール値ではなく、構造化された証拠を返すべきである。
from dataclasses import dataclass
@dataclass(frozen=True)
class CaptchaEvidence:
kind: str
website_url: str
website_key: str
async def detect_recaptcha_v2(page) -> CaptchaEvidence | None:
frame = page.locator('iframe[src*="recaptcha"]')
textarea = page.locator('textarea[name="g-recaptcha-response"]')
if await frame.count() == 0 and await textarea.count() == 0:
return None
key = await page.locator('[data-sitekey]').first.get_attribute('data-sitekey')
if not key:
raise RuntimeError("reCAPTCHA detected without a readable site key")
return CaptchaEvidence(
kind="recaptcha_v2",
website_url=page.url,
website_key=key,
)
入力は、すでに開いているPlaywrightページである。操作は2つの明示的なウィジェットシグナルをチェックし、ページが提供するサイトキーを読み取る。出力はNoneまたはタイプ付き証拠オブジェクトである。チャレンジが表示されているがキーが確認できない場合、エラーで停止する。キーを推測したり、別のページのキーを再利用したりすると、復元が信頼できなくなる。
ソルバーを呼び出す前に、page.urlが許可された小売ホストに属していること、現在の実行が期待される製品とストア識別子を保持していることを検証する。リダイレクトがアカウントページ、チェックアウト、支払いフロー、または予期しないドメインに導く場合、停止しpolicy_deniedをマークする。技術的な能力は、プライベート、制限、機密、または許可されていないデータへのアクセスを許可しない。
公式CapSolver reCAPTCHA v2タスクガイドはReCaptchaV2TaskProxyLess、websiteURL、websiteKeyをドキュメント化している。createTask APIはtaskIdを返し、getTaskResult APIは終端結果を返す。成功したreCAPTCHA v2結果にはsolution.gRecaptchaResponseが含まれる。
import os
import time
import requests
CAPSOLVER_API = "https://api.capsolver.com"
def solve_recaptcha_v2(website_url: str, website_key: str) -> str:
client_key = os.environ["CAPSOLVER_API_KEY"]
created = requests.post(
f"{CAPSOLVER_API}/createTask",
json={
"clientKey": client_key,
"task": {
"type": "ReCaptchaV2TaskProxyLess",
"websiteURL": website_url,
"websiteKey": website_key,
},
},
timeout=30,
).json()
if created.get("errorId") or not created.get("taskId"):
raise RuntimeError(created.get("errorDescription", "createTask failed"))
task_id = created["taskId"]
deadline = time.monotonic() + 120
while time.monotonic() < deadline:
result = requests.post(
f"{CAPSOLVER_API}/getTaskResult",
json={"clientKey": client_key, "taskId": task_id},
timeout=30,
).json()
if result.get("status") == "ready":
token = result.get("solution", {}).get("gRecaptchaResponse")
if not token:
raise RuntimeError("ready result did not contain gRecaptchaResponse")
return token
if result.get("status") == "failed" or result.get("errorId"):
raise RuntimeError(result.get("errorDescription", "CAPTCHA task failed"))
time.sleep(3)
raise TimeoutError("CAPTCHA task exceeded the 120-second deadline")
関数の入力は、検証されたページURLとサイトキーである。操作は正確に1つのタスクを作成し、そのtaskIdのみをポーリングする。出力は文書化されたトークン文字列である。停止条件は明確である:タスク作成エラー、失敗状態、不正な準備完了応答、ネットワークタイムアウト、または120秒の期限。トランスポートリトライは同じタスク結果のHTTPリクエストを繰り返す可能性があるが、新しい課金タスクのシリーズを静かに作成してはならない。
CapSolverボーナスコードを引き換える
自動化予算を即座に増やす!
CapSolverアカウントに資金を追加する際、ボーナスコードCAP26を使用すると、すべての充電で5%のボーナスが追加される—制限なし。
今すぐCapSolverダッシュボードで引き換える
トークンの適用はページに特化している。認証された統合または制御されたテストページでは、トークンを文書化された応答フィールドに書き込み、ページの予期されるコールバックまたは送信パスを呼び出す。新しいブラウザ、別の製品ページ、または別のストアコンテキストにトークンをコピーしないでください。
async def apply_recaptcha_token(page, token: str) -> None:
applied = await page.evaluate(
"""
(token) => {
const fields = [...document.querySelectorAll(
'textarea[name="g-recaptcha-response"]'
)];
if (fields.length === 0) return false;
for (const field of fields) {
field.value = token;
field.innerHTML = token;
field.dispatchEvent(new Event('change', { bubbles: true }));
}
return true;
}
""",
token,
)
if not applied:
raise RuntimeError("reCAPTCHA応答フィールドが適用前に消えました")
この例は、現在のページに表示されている応答フィールドに限定されています。一部の実装では、ドキュメント化されたコールバックも必要です。所有するページまたはテストを許可されたページを検査し、実際の統合契約に接続してください。コールバック名を勝手に作成しないでください。適用後、ウィジェットまたは検証ルートの状態が変化するのを待ってから、在庫操作を再開してください。
在庫検証では、観測された状態を要求された製品と店舗に結合し、保存する必要があります。店舗ラベルが静かに変更された場合や、製品ページがバリアントにリダイレクトされた場合、「利用可能」というセレクターは不十分です。
from datetime import datetime, timezone
async def read_inventory(page, expected_sku: str, expected_store: str) -> dict:
sku = (await page.locator('[data-product-sku]').first.get_attribute('data-product-sku'))
store = (await page.locator('[data-store-id]').first.get_attribute('data-store-id'))
label = (await page.locator('[data-inventory-status]').first.inner_text()).strip()
if sku != expected_sku or store != expected_store:
raise RuntimeError("収集中に製品または店舗コンテキストが変更されました")
normalized = {
"In stock": "in_stock",
"Limited stock": "limited",
"Out of stock": "out_of_stock",
}.get(label)
if not normalized:
raise RuntimeError(f"認識されない在庫ラベル: {label!r}")
return {
"product_id": sku,
"store_id": store,
"availability": normalized,
"observed_at": datetime.now(timezone.utc).isoformat(),
"verification": "product-store-status",
}
セレクターは、あなたが制御するか、自動化する権限を持つページのプレースホルダーです。入力は現在のページと期待される識別子です。操作では、ラベルの正規化の前にアイデンティティをチェックします。出力は検証された在庫記録です。要素が見つからない、識別子が変更された、または認識されないステータスの場合、関数は停止します。これらの停止は、一般的なエラーを防ぐために下流システムを保護します: 変更されたページレイアウトを誤った在庫切れイベントに変換することを防ぎます。
本番環境では、利用可能な場合、2番目の証拠チャネルを追加してください。例として、構造化された製品オブジェクト、ページによって開始されたXHR応答、ピックアップパネルの店舗ラベル、または契約によって許可されたカート資格確認があります。収集者は、アイデンティティと可用性の証拠の間に合意を必要とし、信頼を高めるために単に重複するリクエストを送信しないでください。
予測可能な状態マシンはワークフローを観測可能にし、再帰的な復元を防ぎます。
SCOPED
-> OPEN_PRODUCT
-> CONFIRM_STORE
-> DETECT_CHECKPOINT
-> no challenge: READ_INVENTORY
-> reCAPTCHA v2: CREATE_ONE_TASK
-> ready: APPLY_IN_SAME_SESSION
-> failed/deadline: NEEDS_REVIEW
-> unsupported/ambiguous: NEEDS_REVIEW
-> REPLAY_INVENTORY_ACTION_ONCE
-> VERIFY_PRODUCT + STORE + AVAILABILITY
-> valid: WRITE_RECORD
-> repeated challenge: NEEDS_REVIEW
-> changed context: POLICY_DENIED
ジョブはすべての状態を通じて1つの相関IDを保持する必要があります。遷移の時間と結果を記録してください。解決したトークンやクライアントキーをログに記録しないでください。CapSolverエラーとトラブルシューティングのFAQは、プロバイダーのエラーとブラウザーやアプリケーションのエラーを区別するのに役立ちます。
症状には、サイトキーが見つからない、予期しない検証ページ、またはアダプターが認識しないウィジェットファミリーが含まれます。赤裸々なスクリーンショットとトップレベルのホストをキャプチャしてください。送信しないでください。すべてのiframeをreCAPTCHAとして扱わないでください。
0でないerrorId、失敗したステータス、不正なready結果、またはポーリングの期限切れは、プロバイダー境界のエラーです。taskId、文書化されたエラー説明、経過時間、および相関IDを保持してください。エラークラスが明示的に一時的であり、残りのタスク予算が許可されている場合にのみ再試行してください。
応答フィールドがページが移動、再レンダリング、または店舗コンテキストが変更されたため、消えることがあります。自動的に置き換えられたページにトークンを適用しないでください。スコープとコンテキストの再チェックを実行し、クリーンな状態から単一製品チェックを再開するか、レビューにルーティングしてください。
プロバイダーは、セッション、ページタイミング、ウィジェットメタデータ、またはコールバックパスが一致しない場合、解決済みタスクを返すことがあります。これを適用エラーとして分類してください。1回の制御されたリプレイで十分です。CAPTCHAが繰り返される場合、ループを開始する代わりに停止してください。
ページがロードされますが、在庫証拠が欠如または矛盾している場合、unknownを記録してください。小売業者やテンプレートで曖昧性がしきい値を超えるとアラートを発してください。これは、実際の在庫イベントではなく、マーカップの変更を示すことがよくあります。
HTTPセマンティクス仕様は、トランスポートステータスとアプリケーションの意味を区別するのに役立ちます。200 OKはHTTP応答のみを記述し、場所が選択されたこと、CAPTCHAが受け入れられたこと、または在庫が返されたことを証明しません。
良い在庫自動化は、収集を最小限に抑え、信頼性を最大化します。ビジネスニーズに基づき、ソースが許可する頻度でポーリングしてください。安定した製品メタデータをキャッシュしてください。承認された窓内でジャイタでストアチェックをスケジュールし、バースト性の高い並列リクエストではなく、通常の収集間隔で分離された2回の有効チェックを基準にout_of_stockを通知してください。ソースがサポートする場合は条件付きフェッチを使用し、チャレンジ率やアプリケーションエラー率が予期せずに上昇した場合、実行を停止してください。
これらのメトリクスを別々に追跡してください:
ソルバーの完了のみを最適化しないでください。準備率が高くても受け入れ率が低い場合、統合の問題を示しています。受け入れ率が高くても未知在庫率が上昇している場合、抽出器またはページテンプレートの問題を示しています。メトリクスは、失敗を所有するレイヤーをオペレーターに示す必要があります。
データフィードがアラートを発信する場合、繰り返しの観測を重複排除し、安定性ルールを定義してください。たとえば、通常の収集間隔で分離された2回の有効チェック後にout_of_stockを通知する一方、in_stockの遷移には新しい成功観測が必要です。ルールを構成に表示して、ビジネスチームがアラートが送信された理由を監査できるようにしてください。
所有するページや明示的に自動化を許可されたページでワークフローをテストしてください。通常の在庫状態には固定データを使用し、復元テストには制御されたCAPTCHA統合を使用してください。
createTaskの失敗をモックし、在庫記録が書き込まれないことを確認してください。processing結果をモックし、1つのタスクのみが作成されたことを確認してください。gRecaptchaResponseのない準備完了結果を返し、スキーマ検証が失敗することを確認してください。needs_reviewに進むことを確認してください。out_of_stockではなくunknownであることを確認してください。CAPTCHAソルビングAPIの選択ガイドは追加の評価基準を提供しますが、このユーザーケースの受け入れテストはビジネス固有です: 範囲付きの復元後に正しい製品、正しい店舗、正しい在庫状況を返すシステムである必要があります。
CAPTCHA処理を検証された小売ワークフロー内の制御された状態として扱うことで、店舗在庫データ収集は信頼性が高まります。製品と店舗コンテキストを保持し、1つの文書化されたタスクを作成し、同じ承認されたセッションで解決を適用し、在庫アクションを1回リプレイし、アイデンティティと可用性のチェックが通過した後のみデータを公開してください。CapSolverはCAPTCHAタスクインフラストラクチャを提供しますが、収集者はスコープ、レートリミット、データ品質、停止条件の責任を負います。
Q: ストア在庫データ収集の最小出力は何ですか?
最小信頼性のある出力には、正規化された製品ID、店舗または地域ID、正規化された在庫状況、観測時間、および状態を検証するために使用された証拠が含まれます。空のページや失敗したチェックポイントは絶対に在庫切れに変換しないでください。
Q: CAPTCHA復元中に同じブラウザセッションを保持する必要がありますか?
同じセッションは、チェックポイントに関連するページ、クッキー、製品選択、店舗選択、ウィジェットライフサイクルを保持します。結果を別のコンテキストに移動すると、拒否されるか、間違った店舗に観測が関連付けられる可能性があります。
Q: 在庫ジョブはどのくらいのCAPTCHAリトライを実行する必要がありますか?
小さな明示的な予算を使用してください: 1つのタスクと1つの制御されたアプリケーションリプレイは実用的なデフォルトです。繰り返しのチャレンジはneeds_reviewに進むべきです。これにより、高価または破壊的なループを避けて統合を検査できます。
Q: 準備完了したCapSolverタスクは在庫が収集されたことを証明しますか?
いいえ。準備完了したタスクは、プロバイダーが解決を返したことを証明するだけです。ブラウザーがそれを受け入れ、アプリケーションが認識された製品、店舗、在庫状態を返す必要があります。
Q: 私的小売業者のポータルから在庫を収集できますか?
ポータルの所有者が明示的に自動化を許可し、ワークフローが適用される契約と法律に準拠している場合のみ可能です。技術的な能力は、プライベート、制限、機密、または承認されていないデータへのアクセスを許可しません。
スケーラブルなRustウェブスクレイピングアーキテクチャを学びましょう。リクエスト、スクレイパー、非同期スクレイピング、ヘッドレスブラウザスクレイピング、プロキシローテーション、およびコンプライアンス対応のCAPTCHA処理で。

2026年のデータ・アズ・ア・サービス(DaaS)を理解する。その利点、ユースケース、およびリアルタイムの洞察と拡張性を通じて企業を変革する方法について探る。
