定價搜尋器 (Pricing Finder)
告訴它你的產品網址或描述。它會找出 5 家競爭對手,抓取它們實際的定價頁面,並回傳一份完整的定價情報報告:市場主流定價模式、基準價格表、功能門檻分析、競爭定位圖,以及具體的產品定價策略建議。
無需任何 API 金鑰。 完全依賴免費的 pip 套件即可執行。選用的 API 金鑰可提升分析品質。
零幻覺政策: 輸出中的每個價格點、方案名稱與功能門檻都必須能夠追溯到所抓取的定價頁面內容,或 DuckDuckGo 搜尋摘要。這適用於:
- 競爭對手的價格:僅從抓取的頁面內容中逐字提取
- 「聯絡銷售」:照實記錄,絕不估算或替換為數字
- 方案名稱:完全複製於頁面,不重新詮釋
- 功能列表:從頁面內容提取,不得依賴產品知識推斷
- 定位觀察:僅根據基準價格表的數據推導
常見錯誤
| 代理人可能會想... | 為什麼這樣做不對 |
|---|---|
| 用估算價格填寫「聯絡銷售」 | 永遠不要估算企業級定價。應確實記錄為「聯絡銷售」。 |
| 利用訓練知識填寫競爭對手價格 | 每個價格都必須回溯至抓取的頁面內容或搜尋摘要。 |
| 跳過競爭對手確認步驟 | 務必顯示發現的競爭對手並等待使用者確認。錯誤的競爭對手 = 錯誤的基準。 |
| 不參考基準數據就直接推薦價格 | 每個價格推薦都必須引用基準價格表中的特定數字。 |
| 內容少於 500 字元時仍將頁面標記為高品質 | 少於 500 字元表示頁面可能未被成功抓取 — 應將 data_quality 標記為 'low',並使用搜尋摘要作為備援。 |
| 在輸出中使用長破折號 | 將所有長破折號取代為連字號。 |
每次執行前請先閱讀參考文件
cat references/pricing-models.md
cat references/extraction-guide.md
cat references/positioning-guide.md
步驟 1:環境檢查
echo "TAVILY_API_KEY: ${TAVILY_API_KEY:+set (search quality enhanced)}${TAVILY_API_KEY:-not set, DuckDuckGo will be used (free)}"
echo "FIRECRAWL_API_KEY: ${FIRECRAWL_API_KEY:+set (JS rendering enhanced)}${FIRECRAWL_API_KEY:-not set, requests+BS4 will be used (free)}"
echo ""
python3 -c "from ddgs import DDGS; import requests, bs4, html2text; print('Dependencies OK')" 2>/dev/null \
|| echo "ERROR: Missing dependencies. Run: 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:要抓取的網址(必要,除非使用者直接貼上描述文字)geography:選擇性 — 美國 / 歐洲 / 印度 / 全球。預設:美國
若使用者僅提供貼上的描述文字(無網址): 略過步驟 3 和 4。直接跳至步驟 4(產品分析),並將貼上的文字當作 product_content。設定 page_source 為 user_description,並在 data_quality_flags 中註明。
若沒有網址也沒有描述: 詢問:「請提供您的產品或新創公司的網址?或貼上一段簡短描述:它做什麼、目標對象是誰、以及與眾不同之處。」
步驟 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'Fetched via Firecrawl: {len(content)} characters')
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'Fetched via requests+BS4: {len(content)} characters')
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('ERROR: fewer than 200 characters fetched -- page may be JS-rendered')
else:
print(f'Content OK: {len(content)} characters')
"
若內容少於 200 字元: 告知使用者:「產品頁面回傳的內容太少 — 該網站可能是由 JavaScript 渲染的。請貼上一段簡短描述:您的產品做什麼、目標對象是誰、以及與競爭對手有何不同。」
步驟 4:產品分析(AI)
印出頁面內容:
python3 -c "
content = open('/tmp/pf-product-raw.md').read()[:5000]
print('=== PRODUCT PAGE (first 5000 chars) ===')
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:美國 / 歐洲 / 印度 / 全球page_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('Product analysis written.')
PYEOF
驗證:
python3 -c "
import json
a = json.load(open('/tmp/pf-product-analysis.json'))
print('Product:', a['product_name'])
print('Industry:', a['industry_taxonomy']['l1'], '>', a['industry_taxonomy']['l2'], '>', a['industry_taxonomy']['l3'])
print('Differentiators:')
for d in a['differentiators']:
print(f' - {d}')
"
步驟 4b:第一階段 — 競爭對手發現
ls scripts/research.py 2>/dev/null && echo "script found" || echo "ERROR: scripts/research.py not found -- cannot continue"
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'Searches run: {len(data[\"competitor_searches\"])}')
for s in data['competitor_searches']:
print(f'\nQuery: {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"\nFound 5 competitors for {analysis['product_name']} in {analysis['industry_taxonomy']['l3']}:\n")
for i, c in enumerate(candidates, 1):
print(f" {i}. {c['name']} -- {c['description']}")
print(f" Product: {c['url']}")
print(f" Pricing: {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"Confirmed {len(confirmed)} competitors for pricing research.")
for c in confirmed:
print(f" - {c['name']} | pricing: {c['pricing_url']}")
PYEOF
步驟 6:第二階段 — 抓取定價頁面
python3 scripts/research.py \
--phase fetch-pricing \
--competitors /tmp/pf-competitors-confirmed.json \
--output /tmp/pf-pricing-raw.json
這會使用三層遞迴策略抓取每個競爭對手的定價頁面:
- 直接抓取:
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'Competitors fetched: {data[\"competitors_fetched\"]}')
print()
for r in data['results']:
quality_label = {'high': 'GOOD', 'medium': 'OK', 'low': 'SNIPPET ONLY'}.get(r['data_quality'], r['data_quality'])
print(f' {r[\"name\"]:20} {r[\"source\"]:15} {r[\"content_length\"]:5} chars [{quality_label}]')
"
若某競爭對手的 data_quality: low: 這表示定價頁面被阻擋或用 JavaScript 渲染。分析仍會使用搜尋摘要進行,但該競爭對手的信心水準將標記為較低。
步驟 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\"]} (source: {r[\"source\"]}, quality: {r[\"data_quality\"]}) ===')
print(f'Pricing URL: {r[\"pricing_url\"]}')
print(r['content'][:4000])
print('---')
"
AI 指令: 針對每個競爭對手,從上述內容中提取結構化的定價數據。請遵循 references/extraction-guide.md 中關於如何識別方案、價格、限制和行動呼籲按鈕的指導。
零幻覺規則:
- 僅從內容中逐字提取價格。如果內容中沒有某個價格,則寫
null。 - 將「聯絡銷售」照實記錄。絕不使用估算數字取代。
data_quality: low表示數據來自搜尋摘要 — 請提取存在的資訊,但不要用訓練知識填補缺口。- 對於內容中未出現的任何欄位:請寫
"not found in page data"。 - 年度價格:請同時記錄每月等值金額以及年度總額。
寫入 /tmp/pf-pricing-extracted.json:
python3 << 'PYEOF'
import json
# 填入:每個競爭對手一個物件,遵循以下結構
提取的數據 = [
# {
# "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%" 或 "not found in page data"
# "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, # "Contact Sales"、"Free" 或留空
# "seats": str, # "per seat"、"unlimited"、"up to 5" 等
# "key_limits": [str], # 儲存空間、API 呼叫次數、專案數等
# "key_features": [str] # 該方案中最重要的 3-5 項功能
# }
# ],
# "enterprise_tier": true | false,
# "enterprise_pricing": str, # "Contact Sales" 或實際價格
# "regional_pricing": str | null # 例如 "India: ₹999/mo" 或 null
# }
]
…
[為便於翻譯,此處內容已截斷]