
Sora Fujimoto
AI Solutions Architect

価格や製品データ、保護されたページのコンテンツをスクレイピングしたことがある人は、URLを読み込むことよりも難しいのは、サイトのキャプチャを解決し、そのサイトが期待するように解決されたトークンを送信し、保護された応答から正しいデータを抽出することであることをすでに知っているでしょう。
そのため、単純な「キャプチャを解決して終了」という例は、実際の自動化には十分ではありません。サイトによっては、トークンをヘッダー、フォームボディ、JSONペイロード、クエリ文字列、クッキー、または他のアプリケーション固有のフィールドに送信する必要があります。reCAPTCHA、Turnstile、または他のキャプチャチャレンジを使用する可能性もあります。そして、保護された応答が戻ってきた後でも、セレクターと出力ロジックが目的に合致している必要があります。
このガイドでは、n8n で**CapSolver** を使用してキャプチャ保護サイトのスクレイパーを構築する方法を学びます。メインのウォークスルーは、リポジトリのワークフロー Scraping — Price & Product Details — CapSolver + Schedule + Webhook に基づいていますが、同じテンプレートは以下に適応できます:
この記事は、所有、管理、またはテストが許可されているターゲットでの実用的で認証された自動化についてです。
重要: これらのワークフローは例であり、スタートアップテンプレートであり、万能の即席レシピではありません。各特定のサイトに合わせてキャプチャ設定、トークン送信方法、リクエストペイロード、ヘッダー、クッキー、抽出セレクター、出力ロジックを変更することを期待してください。
この記事のメイン例は、固定ターゲットのスクレイパーのテンプレートで、現在2つのアクティベーションモードをサポートしています:
デフォルトのリポジトリテンプレートでは、このワークフローは:
x-recaptcha-tokenヘッダー経由で送信priceとproductNameを抽出$workflow.staticDataと比較同じパターンは:
として使用できます。
これらのリポジトリテンプレートはすべて、同じ再利用可能な骨格に従います:
トリガー -> キャプチャを解決 -> 保護されたリクエストを送信 -> 結果を抽出 -> 比較/保存/出力
この構造はいくつかの正当な使用ケースに適合します:
| 使用ケース | 変更される内容 |
|---|---|
| スクレイピング | 価格フィールドを抽出し、時間とともに比較 |
| 製品データのスクレイピング | タイトル、SKU、販売者、在庫、または説明などのフィールドを抽出 |
| 在庫チェック | 利用可能テキスト、数量、または購入ボタンの状態を比較 |
| 自分のアカウントにログイン | 解決されたトークンをログインリクエストに送信し、ログイン成功を確認 |
| 保護されたコンテンツの取得 | ゲートされたコンテンツを取得し、抽出されたフィールドを返す |
| Webhookでトリガーされるスクレイピング | 他のサービスが固定された構成済みターゲットを必要に応じてアクティブ化できるようにする |
構造は再利用可能ですが、実際には各サイトで実装の詳細が異なります。実際には、ここにある各ワークフローを例として扱い、解決設定、リクエストの形、トークンの配置、抽出ロジックを自動化するターゲットに合わせて調整する必要があります。
上記のメインスクレイパーのワークフローは、生のページコンテンツを取得し、価格を比較します。以下のワークフローは、同じキャプチャ解決パターン - トリガー → キャプチャを解決 → 保護されたリクエストを送信 → 結果を評価 - を特定の使用ケースに拡張します。それぞれには同じ前提条件が必要です:n8nインスタンス、CapSolverの資格情報、およびターゲットのキャプチャパラメータ。
| ワークフロー | 目的 |
|---|---|
Scraping — Price & Product Details — CapSolver + Schedule + Webhook |
固定ターゲットのスケジュール + Webhookテンプレートで、reCAPTCHA v3を解決し、x-recaptcha-tokenにトークンを送信し、priceとproductNameを抽出し、$workflow.staticDataと値を比較し、スクレイピング、製品詳細抽出、または同様の保護された製品ページのチェックに使用できます |
アクティベーションの注意: このテンプレートは
active: falseとしてインポートされます。Webhookのパスは、プレースホルダーを構成し、CapSolverの資格情報を選択し、n8nでワークフローをアクティブ化するまで有効ではありません。
開始する前に、以下のものを確認してください:
この記事のメイン例では、ターゲットがreCAPTCHAを使用していると仮定されているため、キー値は以下の通りです:
websiteURLwebsiteKeypageAction for reCAPTCHA v3重要: 以下のパラメータの特定のウォークスルーはreCAPTCHAの例に限定されています。実際のターゲットは、Cloudflare Turnstile、Cloudflare Challenge、GeeTest、DataDome、AWS WAF、MTCaptchaなど、別のチャレンジタイプを使用する可能性があります。その場合、解決ノードの設定、必要なフィールド、および保護されたリクエストのパターンが異なります。
reCAPTCHA保護ページの場合、コア値は通常以下の通りです:
| パラメータ | 説明 |
|---|---|
websiteURL |
キャプチャが表示または必要なURL |
websiteKey |
ページで使用される公開サイトキー |
pageAction |
reCAPTCHA v3が期待するアクション文字列 |
リポジトリの価格モニターテンプレートでは、CapSolverノードは以下の通り構成されています:
operation: reCAPTCHA v3websiteURL: https://YOUR-TARGET-SITE.com/product-pagewebsiteKey: YOUR_SITE_KEY_HEREpageAction: view_productreCAPTCHAターゲットを検証する際には、以下のことを確認してください:
pageActionが必要かどうか重要: これは万能のキャプチャ検出セクションではありません。ターゲットが別のチャレンジタイプを使用している場合(例:Cloudflare Turnstile、Cloudflare Challenge、GeeTest、DataDome、AWS WAF、MTCaptcha)では、CapSolverの設定と解決されたトークンを送信するHTTPリクエストを変更する必要があります。
リポジトリのワークフロー Scraping — Price & Product Details — CapSolver + Schedule + Webhook は、2つの固定ターゲットのアクティベーションパスをサポートしています:
Every 6 HoursWebhook Trigger両方のパスは同じターゲットプレースホルダーと同じスクレイパー論理を使用します。Webhookバージョンは単に**Respond to Webhook**で終わるため、呼び出し元が最終的なアラートまたは変更なしペイロードをJSONとして受け取れます。
スケジュールパスには以下のノードが使用されます:
Every 6 HoursSolve reCAPTCHA v3Fetch Product PageExtract DataCompare DataData Changed?Build AlertNo ChangeWebhookパスは同じ論理で同じ固定ターゲットを処理します:
Webhook TriggerSolve reCAPTCHA v3 [Webhook]Fetch Product Page [Webhook]Extract Data [Webhook]Compare Data [Webhook]Data Changed? [Webhook]Build Alert [Webhook]No Change [Webhook]Respond to Webhook定期的なチェック(例:スクレイピングや在庫チェック)が必要な場合はスケジュールを使用します。
他のワークフロー、サービス、またはアプリケーションが同じ構成済みターゲットを必要に応じてアクティブ化する必要がある場合はWebhookを使用します。
テンプレートは以下の設定を使用します:
| 設定 | 値 |
|---|---|
| Operation | reCAPTCHA v3 |
websiteURL |
https://YOUR-TARGET-SITE.com/product-page |
websiteKey |
YOUR_SITE_KEY_HERE |
pageAction |
view_product |
解決されたトークンはリクエストヘッダーに送信されます:
| ヘッダー | 値 |
|---|---|
user-agent |
ブラウザスタイルのユーザーエージェント |
x-recaptcha-token |
{{ $json.data.solution.gRecaptchaResponse }} |
これはワークフローで最も重要な詳細の1つです。リポジトリのテンプレートはトークンが常にg-recaptcha-responseに属するとは仮定していません。この例では、カスタムヘッダーに送信されます。
priceとproductNameを抽出HTMLノードは以下の通り抽出します:
| キー | CSSセレクター |
|---|---|
price |
.product-price, [data-price], .price |
productName |
h1, .product-title |
Codeノードは以下の値を使用して保存と比較を行います:
$workflow.staticData.lastPrice$workflow.staticData.lastCheckedこれにより、ワークフローは以下の違いを判別できます:
IFノードは{{ $json.changed }}をチェックします。
価格が変更された場合、ワークフローは**Build Alert**に進みます。
そうでない場合、**No Change**に進みます。
Webhookパスでは、どちらの分岐も**Respond to Webhook**に進みます。
メインの例には価格比較ロジックが含まれていますが、これは保護された製品ページのスクレイパーのテンプレートに比較ロジックを組み込んだものと考えるのがより有用です。
再利用可能な部分は:
これがなぜ同じ構造が:
をサポートできるのかの理由です。
これは実際のターゲットで最も重要な部分です。
ほとんどの実際のサイトでは、ここにあるほぼすべての内容を調整する必要があります:チャレンジタイプ、解決パラメータ、トークンが送信される場所、リクエストボディ、クッキー、ヘッダー、セレクター、および最終的な成功基準。これらのリポジトリワークフローは、動作可能なパターンの例であり、すべてのサイトにそのまま適合する固定レシピではありません。
リポジトリの使用ケースワークフローは現在スケジュール + Webhookをサポートしています。
使用するには:
これらのテンプレートのWebhookパスは固定ターゲットアクティベーターであり、任意のユーザー提供ターゲットの公開APIではありません。
メインの価格モニターアイテムはreCAPTCHA v3を使用していますが、ターゲットは次のいずれかを使用する可能性があります:
これにより、解決ステップをそれに応じて更新する必要があります。
2つのサイトがともにreCAPTCHAを使用していても、設定は異なる場合があります。
変更が必要な可能性があるのは:
operationまたはタスクタイプwebsiteURLwebsiteKeypageActionスクレイパーのテンプレートは、これらが変更される予定であるため、プレースホルダー構成フィールドとして公開しています。
トークンが常に同じ場所に送信されるとは考えないでください。
このリポジトリではいくつかのパターンがすでに示されています:
| パターン | リポジトリの例 |
|---|---|
| リクエストヘッダー | Scraping — CapSolver + Schedule は x-recaptcha-token を使用 |
| フォームボディ | ログインワークフローは通常フォームエンコードされたボディの g-recaptcha-response を使用 |
実際のサイトでは、解決されたトークンは:
に属する可能性があります。
このリポジトリの例は1つの送信パターンであり、万能ではありません。
保護されたリクエストにはキャプチャやチャレンジトークンだけでなく、他のものが必要な場合があります。
調整が必要なのは:
これは特に:
で一般的です。
メインのスクレイパーのテンプレートは:
priceproductNameを抽出しますが、以下に置き換えることができます:
現在の価格モニターコードは数値値を比較していますが、同じパターンは以下に適応できます:
以下のJSONは、このリポジトリから**Scraping — Price & Product Details — CapSolver + Schedule + Webhook**の現在のインポート可能なバージョンであり、スケジュール + Webhookのアクティベーションパスを含んでいます。
{
"nodes": [
{
"parameters": {
"content": "## Scraping \u2014 Price & Product Monitor\n\n### How it works\n\n1. Triggers either by schedule or webhook input to start price monitoring.\n2. Solves reCAPTCHA to access the targeted product page.\n3. Retrieves and extracts data from the product page for further analysis.\n4. Compares newly fetched data with previously stored data to detect changes.\n5. Determines if changes occurred and prepares alerts if needed.\n6. Sends responses based on data analysis through designated channels.\n\n### Setup steps\n\n- [ ] Configure scheduled trigger interval in 'Every 6 Hours' node.\n- [ ] Set target website details in 'Set Target Config [Schedule]'.\n- [ ] Configure reCAPTCHA solver with API key in 'Solve reCAPTCHA v3' nodes.\n- [ ] Set up Webhook URL and path in 'Webhook Trigger'.\n- [ ] Define alert criteria and destination in 'Build Alert' nodes.\n\n### Customization\n\nAdjust the extraction pattern in 'Extract Data' nodes to fit specific product details.",
"height": 896,
"width": 480
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1328,
-304
],
"id": "52c7808e-d2bc-4779-85e6-909a51066338",
"name": "Sticky Note"
},
{
"parameters": {
"content": "## Scheduled trigger setup\n\nInitializes the data monitoring process every 6 hours using a schedule trigger and sets the target configuration for scraping.",
"height": 320,
"width": 496,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-752,
-160
],
"id": "3c5cee67-552d-48ea-8717-7c5126269e2e",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## スケジュールされたスクリーニングプロセス\n\nスケジュールされたトリガーに従って、reCAPTCHAを解決し、製品ページを取得し、データを抽出して以前の記録と比較して変更を識別します。",
"height": 496,
"width": 1680,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-144,
-304
],
"id": "d0315be2-111c-4893-bf42-2f2cc2eb186f",
"name": "Sticky Note2"
},
{
"parameters": {
"content": "## Webhookトリガーのセットアップ\n\nインバウンドWebhook経由で手動でトリガーされるデータモニタリングを処理し、進むためにreCAPTCHAを解決します。",
"height": 304,
"width": 816,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-768,
336
],
"id": "a78f1606-07fb-40fd-af82-e1dc9b766206",
"name": "Sticky Note3"
},
{
"parameters": {
"content": "## Webhookスクリーニングプロセス\n\nWebhookトリガーされたリクエストを処理し、製品ページを取得し、データを抽出し、変更を判断します。",
"height": 272,
"width": 1088,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
160,
320
],
"id": "1a677fd9-a3a8-404f-ba9a-2b087d7bfe11",
"name": "Sticky Note4"
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 6
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [
-704,
0
],
"id": "sc-901",
"name": "6時間ごと"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-001",
"name": "websiteURL",
"value": "https://YOUR-TARGET-SITE.com/product-page",
"type": "string"
},
{
"id": "cfg-002",
"name": "websiteKey",
"value": "YOUR_SITE_KEY_HERE",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-400,
0
],
"id": "sc-900",
"name": "Set Target Config [Schedule]"
},
{
"parameters": {
"operation": "reCAPTCHA v3",
"websiteURL": "={{ $json.websiteURL }}",
"websiteKey": "={{ $json.websiteKey }}",
"optional": {
"pageAction": "view_product"
}
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [
-96,
0
],
"id": "sc-902",
"name": "Solve reCAPTCHA v3",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "CapSolver account"
}
}
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Target Config [Schedule]').first().json.websiteURL }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "user-agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
},
{
"name": "x-recaptcha-token",
"value": "={{ $json.data.solution.gRecaptchaResponse }}"
}
]
},
"options": {
"response": {
"response": {}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
208,
0
],
"id": "sc-903",
"name": "Fetch Product Page"
},
{
"parameters": {
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "price",
"cssSelector": ".product-price, [data-price], .price"
},
{
"key": "productName",
"cssSelector": "h1, .product-title"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.html",
"typeVersion": 1.2,
"position": [
512,
0
],
"id": "sc-904",
"name": "Extract Data"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\nconst parsePrice = (str) => { if (!str) return null; const match = str.match(/[\\d,]+\\.?\\d*/); return match ? parseFloat(match[0].replace(',', '')) : null; };\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'first check', changed, direction, diff: changed ? `$${diff}` : null, checkedAt: new Date().toISOString() } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
800,
0
],
"id": "sc-905",
"name": "Compare Data"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "if-1",
"leftValue": "={{ $json.changed }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1104,
0
],
"id": "sc-906",
"name": "Data Changed?"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a1",
"name": "alert",
"value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
"type": "string"
},
{
"id": "a2",
"name": "severity",
"value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}",
"type": "string"
},
{
"id": "a3",
"name": "checkedAt",
"value": "={{ $json.checkedAt }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1392,
-192
],
"id": "sc-907",
"name": "Build Alert"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "n1",
"name": "status",
"value": "no_change",
"type": "string"
},
{
"id": "n2",
"name": "currentPrice",
"value": "={{ $json.currentPrice }}",
"type": "string"
},
{
"id": "n3",
"name": "checkedAt",
"value": "={{ $json.checkedAt }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1392,
32
],
"id": "sc-908",
"name": "No Change"
},
{
"parameters": {
"httpMethod": "POST",
"path": "price-monitor",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-720,
464
],
"id": "sc-909",
"name": "Webhook Trigger",
"webhookId": "sc-909-webhook",
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "reCAPTCHA v3",
"websiteURL": "={{ $json.body.websiteURL }}",
"websiteKey": "={{ $json.body.websiteKey }}",
"optional": {
"pageAction": "={{ $json.body.pageAction || 'view_product' }}"
}
},
"type": "n8n-nodes-capsolver.capSolver",
"typeVersion": 1,
"position": [
-96,
464
],
"id": "sc-910",
"name": "Solve reCAPTCHA v3 [Webhook]",
"credentials": {
"capSolverApi": {
"id": "BeBFMAsySMsMGeE9",
"name": "CapSolver account"
}
}
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Webhook Trigger').item.json.body.websiteURL }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "user-agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
},
{
"name": "x-recaptcha-token",
"value": "={{ $json.data.solution.gRecaptchaResponse }}"
}
]
},
"options": {
"response": {
"response": {}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
208,
432
],
"id": "sc-911",
"name": "Fetch Product Page [Webhook]"
},
{
"parameters": {
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "price",
"cssSelector": ".product-price, [data-price], .price"
},
{
"key": "productName",
"cssSelector": "h1, .product-title"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.html",
"typeVersion": 1.2,
"position": [
512,
432
],
"id": "sc-912",
"name": "Extract Data [Webhook]"
},
{
"parameters": {
"jsCode": "const staticData = $workflow.staticData;\nconst currentPrice = $input.first().json.price;\nconst previousPrice = staticData.lastPrice;\nconst productName = $input.first().json.productName || 'Product';\nconst parsePrice = (str) => { if (!str) return null; const match = str.match(/[\\d,]+\\.?\\d*/); return match ? parseFloat(match[0].replace(',', '')) : null; };\nconst currentNum = parsePrice(currentPrice);\nconst previousNum = parsePrice(previousPrice);\nstaticData.lastPrice = currentPrice;\nstaticData.lastChecked = new Date().toISOString();\nconst changed = previousNum !== null && currentNum !== null && currentNum !== previousNum;\nconst direction = changed ? (currentNum < previousNum ? 'dropped' : 'increased') : 'unchanged';\nconst diff = changed ? Math.abs(currentNum - previousNum).toFixed(2) : '0';\nreturn [{ json: { productName, currentPrice, previousPrice: previousPrice || 'first check', changed, direction, diff: changed ? `$${diff}` : null, checkedAt: new Date().toISOString() } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
800,
432
],
"id": "sc-913",
"name": "Compare Data [Webhook]"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "if-2",
"leftValue": "={{ $json.changed }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1104,
432
],
"id": "sc-914",
"name": "Data Changed? [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a4",
"name": "alert",
"value": "=Price {{ $json.direction }} for {{ $json.productName }}: {{ $json.previousPrice }} \u2192 {{ $json.currentPrice }}",
"type": "string"
},
{
"id": "a5",
"name": "severity",
"value": "={{ $json.direction === 'dropped' ? 'deal' : 'info' }}",
"type": "string"
},
{
"id": "a6",
"name": "checkedAt",
"value": "={{ $json.checkedAt }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1424,
384
],
"id": "sc-915",
"name": "Build Alert [Webhook]"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "n4",
"name": "status",
"value": "no_change",
"type": "string"
},
{
"id": "n5",
"name": "currentPrice",
"value": "={{ $json.currentPrice }}",
"type": "string"
},
{
"id": "n6",
"name": "checkedAt",
"value": "={{ $json.checkedAt }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1440,
592
],
"id": "sc-916",
"name": "No Change [Webhook]"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
1712,
512
],
"id": "sc-917",
"name": "Respond to Webhook"
}
],
"connections": {
"6時間ごと": {
"main": [
[
{
"node": "ターゲット設定のスケジュールを設定",
"type": "main",
"index": 0
}
]
]
},
"ターゲット設定のスケジュールを設定": {
"main": [
[
{
"node": "reCAPTCHA v3を解決",
"type": "main",
"index": 0
}
]
]
},
"reCAPTCHA v3を解決": {
"main": [
[
{
"node": "製品ページを取得",
"type": "main",
"index": 0
}
]
]
},
"製品ページを取得": {
"main": [
[
{
"node": "データを抽出",
"type": "main",
"index": 0
}
]
]
},
"データを抽出": {
"main": [
[
{
"node": "データを比較",
"type": "main",
"index": 0
}
]
]
},
"データを比較": {
"main": [
[
{
"node": "データが変更されましたか?",
"type": "main",
"index": 0
}
]
]
},
"データが変更されましたか?": {
"main": [
[
{
"node": "アラートを構築",
"type": "main",
"index": 0
}
],
[
{
"node": "変更なし",
"type": "main",
"index": 0
}
]
]
},
"Webhookトリガー": {
"main": [
[
{
"node": "reCAPTCHA v3 [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"reCAPTCHA v3 [Webhook]": {
"main": [
[
{
"node": "製品ページを取得 [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"製品ページを取得 [Webhook]": {
"main": [
[
{
"node": "データを抽出 [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"データを抽出 [Webhook]": {
"main": [
[
{
"node": "データを比較 [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"データを比較 [Webhook]": {
"main": [
[
{
"node": "データが変更されましたか? [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"データが変更されましたか? [Webhook]": {
"main": [
[
{
"node": "アラートを構築 [Webhook]",
"type": "main",
"index": 0
}
],
[
{
"node": "変更なし [Webhook]",
"type": "main",
"index": 0
}
]
]
},
"アラートを構築 [Webhook]": {
"main": [
[
{
"node": "Webhookに応答",
"type": "main",
"index": 0
}
]
]
},
"変更なし [Webhook]": {
"main": [
[
{
"node": "Webhookに応答",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"instanceId": "962ff0267b713be0344b866fa54daae28de8ed2144e2e6867da355dae193ea1f"
}
}
プレースホルダーを構成し、ワークフローを有効にした後、Webhookのパスをトリガーしてください:
curl -X POST https://your-n8n-instance.com/webhook/price-monitor \
-H "Content-Type: application/json" \
-d '{}'
期待される応答(最初のチェック):
{
"status": "no_change",
"currentPrice": "$29.99",
"checkedAt": "2026-03-11T08:00:00.000Z"
}
期待される応答(価格が変更された場合):
{
"alert": "Widget Proの価格が下がりました: $39.99 → $29.99 (-$10.00)",
"severity": "deal",
"checkedAt": "2026-03-11T14:00:00.000Z"
}
実際の価格データが含まれた応答は、パイプライン全体が動作したことを確認します — CAPTCHAが解決され、保護されたページが取得され、データが抽出され、比較ロジックが実行されました。
CapSolverがトークンを返すが、サイトが依然としてリクエストをブロックしている場合、問題は解決自体にあるとは限りません。一般的な原因は次の通りです:
pageActionターゲットがreCAPTCHA以外のチャレンジ — 例えばCloudflare Turnstile、Cloudflare Challenge、GeeTest、DataDome、AWS WAF、またはMTCaptcha — を使用している場合、メインの例は変更せずに動作しません。次を更新する必要があります:
HTMLノードが予期したフィールドを抽出しない場合:
リポジトリのテンプレートは非アクティブでインポートされます。以下の手順を完了するまで:
Webhookのパスは有効になりません。
Build Alertまたは認証成功/失敗ノードの後に、下流の通知またはストレージノードを追加してください。開始する準備はできましたか? CapSolverに登録し、初回チャージで6%のボーナスを追加するバーコードOPENCLAWを使用してください!
主なポイントは単純です:CAPTCHAを解決することはワークフローの1つのステップにすぎません。実際のスクリーパーは、トークンを正しい方法で送信し、正しいリクエストの形を送信し、使用ケースに必要なフィールドを抽出する必要があります。
これはまた、これらのテンプレートが例として扱われるべきである理由です。別のサイトは、別のCAPTCHAタイプを使用し、トークンを別の場所に期待し、追加のcookiesやフィールドを必要とし、異なる応答の形を返し、異なる抽出または検証ロジックを必要とする可能性があります。
このテンプレートは次のためのスタートアップを提供します:
これは次の広範なパターンを使用します:
トリガー -> CAPTCHAを解決 -> 保護されたリクエストを送信 -> 結果を抽出または検証 -> 出力
プレースホルダーを構成し、ワークフローをターゲットに一致させるまで非アクティブに保ち、使用ケースに合ったスケジュールまたはWebhookパスを有効にしてください。
スクリーパーテンプレートは、認証トークンとともに資格情報をPOSTするHTTPリクエストノードを変更することで、ログインフローに適応できます。reCAPTCHA、Turnstileなどの専用のCAPTCHAタイプガイドを参照してください。準備済みのログインワークフローテンプレートが用意されています。
その場合、ワークフローを変更する必要があります。メインの例のreCAPTCHA設定とリクエストパターンは万能ではありません。CapSolverはCloudflare Turnstile、Cloudflare Challenge、GeeTest V3/V4、DataDome、AWS WAF、MTCaptchaなどに対応しています。CapSolverの解決ステップと保護されたリクエストを、ターゲットで使用されている実際のチャレンジタイプとトークン送信パターンに更新してください。
ターゲットサイトが期待する場所に送信してください。これは次の可能性があります:
価格モニターテンプレートはヘッダーを使用します。他のサイトは異なります。
通常はい。同じCAPTCHAファミリーを使用するサイトでも、websiteURL、websiteKey、pageAction、非表示設定、またはその他のタスクオプションが異なる場合があります。
はい。選択肢や出力ロジックを交換して、在庫、タイトル、SKU、説明、保護されたコンテンツ、ログイン状態、サイトの健全性信号などが必要に応じて使用できます。
保護された応答をHTTPリクエストノードから確認することから始めます。
この順序でワークフローをデバッグしてください:解決 -> 送信 -> 応答を確認 -> 抽出。
CapSolverとn8nを使用してeCAPTCHA v2/v3ソルバーAPIを構築します。トークンの自動取得、ウェブサイトへの送信、保護されたデータの抽出をノーコードで自動化する方法を学びます。

画像パズルを解く最高のAIを発見してください。CapSolverのVision EngineとImageToText APIが、高い精度で複雑な視覚的課題を自動化する方法を学びましょう。
