Pricing Finder(価格調査ツール) は何をしますか?
製品のURLまたは説明文を入力してください。5社の競合他社を見つけ、実際の価格ページを取得し、完全な価格インテリジェンスレポートを生成します。レポートには、同市場の支配的な価格モデル、ベンチマーク価格表、機能ゲート分析、ポジショニングマップ、そして自社製品に対する具体的な価格推奨が含まれます。
APIキーは不要です。 すべて無料のpip依存パッケージで動作します。オプションのAPIキーを使用すると品質が向上します。
ゼロ幻覚ポリシー: 出力に含まれるすべての価格、ティア名、機能ゲートは、必ず取得した価格ページのコンテンツまたはDuckDuckGo検索スニペットに基づいている必要があります。これは以下の項目に適用されます:
- 競合の価格: 取得したページコンテンツからそのまま抽出
- 「問い合わせ」: そのまま記録し、決して推定値や数字に置き換えない
- ティア名: ページから正確にコピーし、言い換えない
- 機能リスト: ページコンテンツから抽出し、プロダクト知識から推測しない
- ポジショニングの観察: ベンチマークテーブルのデータのみから導出
よくある間違い
| エージェントがやりがちな行動 | なぜそれが間違っているのか |
|---|---|
| 「問い合わせ」を推定価格に置き換える | エンタープライズ価格を決して推定しない。「問い合わせ」として正確に記録すること |
| トレーニング知識を使って競合価格を補完する | すべての価格は取得したページコンテンツまたは検索スニペットに基づく必要がある |
| 競合確認ステップをスキップする | 常に発見した競合を表示し、確認を待つこと。間違った競合 = 間違ったベンチマーク |
| ベンチマークデータを参照せずに価格を推奨する | すべての価格推奨はベンチマークテーブルの特定の数値を引用しなければならない |
| コンテンツが500文字未満のページを高品質とマークする | 500文字未満はページが取得できなかったことを意味する。data_qualityを'low'とし、検索スニペットフォールバックを使用する |
| 出力にemダッシュ(—)を使用する | すべてのemダッシュをハイフン(-)に置き換えること |
実行前にリファレンスファイルを読む
cat references/pricing-models.md
cat references/extraction-guide.md
cat references/positioning-guide.md
ステップ1: セットアップ確認
echo "TAVILY_API_KEY: ${TAVILY_API_KEY:+set (検索品質向上)}${TAVILY_API_KEY:-未設定、DuckDuckGoを使用 (無料)}"
echo "FIRECRAWL_API_KEY: ${FIRECRAWL_API_KEY:+set (JSレンダリング対応)}${FIRECRAWL_API_KEY:-未設定、requests+BS4を使用 (無料)}"
echo ""
python3 -c "from ddgs import DDGS; import requests, bs4, html2text; print('依存関係OK')" 2>/dev/null \
|| echo "エラー: 依存関係が不足しています。インストールしてください: pip install ddgs requests beautifulsoup4 html2text"
依存関係が不足している場合: すぐに停止し、ユーザーに伝えてください: 「Pythonの依存関係が不足しています。インストールするには以下を実行してください: pip install ddgs requests beautifulsoup4 html2text -- すべて無料でアカウント不要です。その後再試行してください。」
APIキーのみ不足している場合: 続行してください。DuckDuckGoとrequests+BS4が無料のデフォルトです。
製品スラッグを取得:
PRODUCT_SLUG=$(python3 -c "
from urllib.parse import urlparse
import sys, re
url = 'URL_HERE'
if url.startswith('http'):
host = urlparse(url).netloc.replace('www.', '')
print(host.split('.')[0])
else:
print(re.sub(r'[^a-z0-9]', '-', url[:30].lower()).strip('-'))
")
echo "Product slug: $PRODUCT_SLUG"
ステップ2: 入力の解析
会話から以下を収集:
product_url: 取得するURL(必須、ただしユーザーが直接説明文を貼り付ける場合は除く)geography: オプション -- US / Europe / India / global。デフォルト: US
ユーザーがURLなしで説明文のみを貼り付けた場合: ステップ3と4をスキップし、貼り付けられたテキストをproduct_contentとしてステップ4(製品分析)に直接進んでください。page_sourceをuser_descriptionに設定し、data_quality_flagsに注意事項を記載します。
URLも説明文もない場合: 質問してください: 「あなたの製品またはスタートアップのURLを教えてください。または、短い説明文を貼り付けてください: 何をするものか、誰のためのものか、何が他と違うのか。」
ステップ3: 製品ページの取得
プライマリ: Firecrawl(FIRECRAWL_API_KEYが設定されている場合)
curl -s -X POST https://api.firecrawl.dev/v1/scrape \
-H "Authorization: Bearer $FIRECRAWL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "URL_HERE", "formats": ["markdown"], "onlyMainContent": true}' \
| python3 -c "
import sys, json
d = json.load(sys.stdin)
content = d.get('data', {}).get('markdown', '') or d.get('markdown', '')
print(f'Firecrawl経由で取得: {len(content)} 文字')
open('/tmp/pf-product-raw.md', 'w').write(content)
"
フォールバック: requests + BS4(無料、常に利用可能)
python3 << 'PYEOF'
import requests, html2text, random
USER_AGENTS = [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
]
headers = {"User-Agent": random.choice(USER_AGENTS), "Accept": "text/html,application/xhtml+xml;q=0.9,*/*;q=0.8"}
resp = requests.get("URL_HERE", headers=headers, timeout=20, allow_redirects=True)
converter = html2text.HTML2Text()
converter.ignore_images = True
converter.body_width = 0
content = converter.handle(resp.text)[:8000]
print(f'requests+BS4経由で取得: {len(content)} 文字')
open('/tmp/pf-product-raw.md', 'w').write(content)
PYEOF
チェックポイント:
python3 -c "
content = open('/tmp/pf-product-raw.md').read()
if len(content) < 200:
print('エラー: 200文字未満しか取得できませんでした。ページがJSレンダリングされている可能性があります')
else:
print(f'コンテンツOK: {len(content)} 文字')
"
コンテンツが200文字未満の場合: ユーザーに伝えてください: 「製品ページから十分なコンテンツが取得できませんでした。サイトがJavaScriptレンダリングを使用している可能性があります。製品の短い説明文を貼り付けてください: 何をするものか、誰のためのものか、競合と何が違うのか。」
ステップ4: 製品分析(AI)
ページコンテンツを表示:
python3 -c "
content = open('/tmp/pf-product-raw.md').read()[:5000]
print('=== 製品ページ(最初の5000文字)===')
print(content)
"
AI指示: 上記の製品ページを分析し、以下を抽出:
product_name: 製品名または会社名one_line_description: 何をするものか、誰のためのものか、コアバリュープロポジション。20語未満。マーケティング用語は使わない。industry_taxonomy:l1(最上位: developer tools / fintech / healthtech / consumer / など)、l2(セクター: devops / payments / hr / など)、l3(特定ニッチ: CI/CD automation / embedded payments / async video / など)differentiators: この製品を差別化する具体的な要素を正確に2〜3個。これらは推奨に使用されるため、具体的に記述すること。「使いやすい」のような一般的な回答は不可。icp:buyer_persona(職種)、company_type、company_sizegeography_bias: US / Europe / India / globalpage_source: "live_page" または "user_description"
/tmp/pf-product-analysis.jsonに書き込み:
python3 << 'PYEOF'
import json
analysis = {
# 上記の分析結果をここに記入
"product_name": "",
"one_line_description": "",
"industry_taxonomy": {"l1": "", "l2": "", "l3": ""},
"differentiators": [],
"icp": {"buyer_persona": "", "company_type": "", "company_size": ""},
"geography_bias": "US",
"page_source": "live_page"
}
json.dump(analysis, open('/tmp/pf-product-analysis.json', 'w'), indent=2)
print('製品分析を書き込みました。')
PYEOF
確認:
python3 -c "
import json
a = json.load(open('/tmp/pf-product-analysis.json'))
print('製品:', a['product_name'])
print('業界:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('差別化要因:')
for d in a['differentiators']:
print(f' - {d}')
"
ステップ4b: フェーズ1 -- 競合発見
ls scripts/research.py 2>/dev/null && echo "スクリプトが見つかりました" || echo "エラー: scripts/research.py が見つかりません -- 続行できません"
python3 scripts/research.py \
--phase discover \
--product-analysis /tmp/pf-product-analysis.json \
--output /tmp/pf-competitors-raw.json
結果をAIレビュー用に表示:
python3 -c "
import json
data = json.load(open('/tmp/pf-competitors-raw.json'))
print(f'実行した検索: {len(data[\"competitor_searches\"])}')
for s in data['competitor_searches']:
print(f'\nクエリ: {s[\"query\"]}')
for r in s.get('results', [])[:6]:
print(f' - {r[\"title\"]} | {r[\"url\"]}')
print(f' {r.get(\"snippet\",\"\")[:150]}')
"
AI指示: 上記の検索結果を読み、以下の条件を満たす競合企業を正確に5社選択:
- 検索結果のタイトルまたはスニペットに名前が記載されている
- 分析対象製品と同じL3ニッチに属する
- 実際のソフトウェア製品である(代理店、リスト記事、レビューサイトではない)
- 互いに異なる企業である
各競合について以下を記述: name、url、pricing_url(価格ページ。スニペットに見つからない場合は [url]/pricing と推測)、description(スニペットからの一文)、source_url。
ステップ5: 競合確認
python3 << 'PYEOF'
import json
analysis = json.load(open('/tmp/pf-product-analysis.json'))
# 記入: 上記検索結果からの5社の競合
candidates = [
# {"name": str, "url": str, "pricing_url": str, "description": str, "source_url": str}
]
print(f"\n{analysis['product_name']}の {analysis['industry_taxonomy']['l3']} における競合5社を発見しました:\n")
for i, c in enumerate(candidates, 1):
print(f" {i}. {c['name']} -- {c['description']}")
print(f" 製品: {c['url']}")
print(f" 価格: {c['pricing_url']}")
data = json.load(open('/tmp/pf-competitors-raw.json'))
data['competitor_candidates'] = candidates
json.dump(data, open('/tmp/pf-competitors-raw.json', 'w'), indent=2)
PYEOF
ユーザーに伝えてください: 「これらは価格データを取得する5社の競合です。追加、削除、変更がある場合はお知らせください。または「問題ない」と言って続行してください。」
確認を待つ。 ユーザーがリストを編集した場合は、それに応じて候補を更新します。その後、確認済みリストを書き込みます:
python3 << 'PYEOF'
import json
# 記入: 確認済みの競合リスト(ユーザーレビュー後)
confirmed = [
# {"name": str, "url": str, "pricing_url": str}
]
json.dump({"confirmed_competitors": confirmed}, open('/tmp/pf-competitors-confirmed.json', 'w'), indent=2)
print(f"価格調査のための競合 {len(confirmed)} 社を確認しました。")
for c in confirmed:
print(f" - {c['name']} | 価格: {c['pricing_url']}")
PYEOF
ステップ6: フェーズ2 -- 価格ページの取得
python3 scripts/research.py \
--phase fetch-pricing \
--competitors /tmp/pf-competitors-confirmed.json \
--output /tmp/pf-pricing-raw.json
これは、各競合の価格ページを3段階のフォールバックで取得します:
- 直接取得:
requests+beautifulsoup4+html2text - Googleキャッシュ:
webcache.googleusercontent.com/search?q=cache:[url] - DuckDuckGo検索:
"[competitor]" pricing plans cost per month(スニペットフォールバック)
取得サマリーを表示:
python3 -c "
import json
data = json.load(open('/tmp/pf-pricing-raw.json'))
print(f'取得した競合数: {data[\"competitors_fetched\"]}')
print()
for r in data['results']:
quality_label = {'high': '良好', 'medium': '許容', 'low': 'スニペットのみ'}.get(r['data_quality'], r['data_quality'])
print(f' {r[\"name\"]:20} {r[\"source\"]:15} {r[\"content_length\"]:5} 文字 [{quality_label}]')
"
競合のdata_qualityがlowの場合: 価格ページがブロックされたかJSレンダリングされていることを意味します。分析は検索スニペットを使用して続行されますが、その競合に対する信頼度は低いと記録されます。
ステップ7: 価格抽出(AI)
すべての生の価格コンテンツを表示:
python3 -c "
import json
data = json.load(open('/tmp/pf-pricing-raw.json'))
for r in data['results']:
print(f'\n=== {r[\"name\"]} (ソース: {r[\"source\"]}, 品質: {r[\"data_quality\"]}) ===')
print(f'価格URL: {r[\"pricing_url\"]}')
print(r['content'][:4000])
print('---')
"
AI指示: 各競合について、上記のコンテンツから構造化価格データを抽出してください。ティアの識別方法、価格、制限、CTAの特定方法については references/extraction-guide.md に従ってください。
ゼロ幻覚ルール:
- 価格はコンテンツからのみそのまま抽出すること。価格がコンテンツにない場合は
nullと記述すること。 - 「問い合わせ」はそのまま記録すること。決して推定値で置き換えないこと。
data_quality: lowはデータが検索スニペットからのものであることを意味する。そこにあるものは抽出するが、トレーニング知識でギャップを埋めないこと。- コンテンツに存在しないフィールドは、
"ページデータに見つかりません"と記述すること。 - 年額料金: 常に月額換算額を年間合計とともに記録すること。
/tmp/pf-pricing-extracted.jsonに書き込み:
python3 << 'PYEOF'
import json
# 記入: 以下のスキーマに従って、各競合につき1つのオブジェクト
extracted = [
# {
# "competitor": str,
# "pricing_url": str,
# "data_quality": "high" | "medium" | "low",
# "pricing_model": "per-seat" | "flat-rate" | "usage-based" | "freemium" | "tiered-flat" | "hybrid",
# "billing_cadence": ["monthly"] | ["annual"] | ["monthly", "annual"],
# "annual_discount": str, # 例: "20%" または "ページデータに見つかりません"
# "free_tier": true | false,
# "free_trial": true | false,
# "free_trial_days": int | null,
# "tiers": [
# {
# "name": str,
# "price_monthly": float | null, # 問い合わせの場合はnull
# "price_annual_monthly": float | null, # 年額払いの場合の月額換算
# "price_note": str, # "問い合わせ"、"無料"、または空文字
# "seats": str, # "1席あたり"、"無制限"、"最大5席" など
# "key_limits": [str], # ストレージ、APIコール数、プロジェクト数など
# "key_features": [str] # このティアのトップ3〜5機能
# }
# ],
# "enterprise_tier": true | false,
# "enterprise_pricing": str, # "問い合わせ" または実際の価格
# "regional_pricing": str | null # 例: "インド: ₹999/月" または null
# }
]
…
[以下、翻訳対象外のためスキップ]
PYEOF
ステップ8: 価格モデル分析(AI)
python3 scripts/research.py \
--phase analyze-models \
--extracted /tmp/pf-pricing-extracted.json \
--output /tmp/pf-model-analysis.json
AI指示: 抽出されたデータと references/pricing-models.md に基づいて、同市場の支配的な価格モデルを特定してください。以下の観点を分析:
- 最も一般的な課金モデル(シート単価、フラットレート、使用量ベースなど)
- 標準的な課金サイクルと年間割引率
- 無料ティア vs 無料トライアルの普及率
- 価格バンド(例: $10-30/月の小規模、$50-150/月の中規模、$200+/月のエンタープライズ)
- 機能ゲートパターン(各ティアで何がロックされているか)
ステップ9: 価格戦略推奨(AI)
AI指示: 製品分析(ステップ4)、抽出された競合価格データ(ステップ7)、価格モデル分析(ステップ8)、および references/positioning-guide.md を組み合わせて、以下を含む完全な価格戦略推奨を生成してください:
1. 推奨価格モデル
- 採用すべきモデル
- その理由(競合データから引用)
2. 推奨価格(具体的な数字)
- 少なくとも2つのティア
- 各ティアの月額価格
- 各価格が設定された根拠(ベンチマークテーブルの具体的な数値を引用)
3. 機能ゲート戦略
- 各ティアで何を提供するか
- 次のティアで何をロックするか
4. 利用開始戦略
- 無料ティア / 無料トライアル / デモ
5. 市場ポジショニング
- 製品を価格面でどのようにポジショニングするか
- 競合と比較した主な差別化要因
推奨を /tmp/pf-recommendation.md に書き込み:
python3 << 'PYEOF'
recommendation = """ここに完全な価格戦略推奨を記述...
"""
with open('/tmp/pf-recommendation.md', 'w') as f:
f.write(recommendation)
PYEOF
ステップ10: レポート生成
python3 scripts/research.py \
--phase generate-report \
--product-analysis /tmp/pf-product-analysis.json \
--extracted /tmp/pf-pricing-extracted.json \
--model-analysis /tmp/pf-model-analysis.json \
--recommendation /tmp/pf-recommendation.md \
--output /tmp/pf-report.md
レポートを表示:
cat /tmp/pf-report.md
エラーハンドリング
| シナリオ | 対応 |
|---|---|
| DuckDuckGoがレート制限 | 応答を待ってから再試行。持続する場合はユーザーにTavily APIキーを勧める |
| 価格ページが403/ブロックされる | Googleキャッシュフォールバックを試行。それも失敗したらスニペットフォールバック |
| スニペットフォールバックでも価格が見つからない | その競合を「価格データなし」とマークし、利用可能な競合のみで続行 |
| 競合が5社未満しか発見されない | 発見されたもので続行。出力にその旨を記載 |
| 製品JSONに必須フィールドが欠けている | 空の文字列のままにせず、"not found" と設定 |
| ユーザーが確認ステップから戻る | リストを更新し、再確認を促す |
| 中間ファイルがない | 各ステップで説明を出力しながらやり直す |
付録: スクリプトリファレンス
scripts/research.py
このスクリプトは以下のフェーズを処理します:
discover: DuckDuckGo/Tavilyを使用した競合発見検索fetch-pricing: 各競合の価格ページを取得(3段階フォールバック)analyze-models: 価格モデルのパターンを分析generate-report: 完全な価格インテリジェンスレポートを生成
各フェーズは前のフェーズの出力を必要とします。コマンドライン引数で対応します。
動的インポート vs サブプロセス
research.pyはスクリプトとして実行されるため(python3 scripts/research.py ...)、Python内から直接関数をインポートするのではなくサブプロセス経由で実行されます。これにより同じPythonプロセスの競合状態を防ぎます。
付録: 中間ファイル
| ファイル | 内容 | 作成元 |
|---|---|---|
/tmp/pf-product-raw.md | 製品ページのMarkdown | ステップ3 |
/tmp/pf-product-analysis.json | 構造化製品分析 | ステップ4 |
/tmp/pf-competitors-raw.json | 生の競合検索結果 | ステップ4b |
/tmp/pf-competitors-confirmed.json | 確認済み競合リスト | ステップ5 |
/tmp/pf-pricing-raw.json | 取得した価格ページコンテンツ | ステップ6 |
/tmp/pf-pricing-extracted.json | 構造化価格抽出データ | ステップ7 |
/tmp/pf-model-analysis.json | 価格モデル分析結果 | ステップ8 |
/tmp/pf-recommendation.md | 価格戦略推奨のドラフト | ステップ9 |
/tmp/pf-report.md | 最終出力レポート | ステップ10 |