Pricing Finder
제품 URL 또는 설명을 입력하세요. 글로벌 5개 경쟁사를 찾아 실제 가격 페이지를 가져오고, 완전한 가격 인텔리전스 보고서를 반환합니다: 해당 분야의 지배적 모델, 벤치마크 가격표, 기능별 게이트 분석, 포지셔닝 맵, 그리고 제품에 대한 구체적인 가격 추천.
API 키가 전혀 필요하지 않습니다. 무료 pip 의존성만으로 완전히 실행됩니다. 선택적 API 키는 품질을 향상시킵니다.
무-환각 정책: 출력의 모든 가격대, 티어 이름, 기능 게이트는 가져온 가격 페이지 콘텐츠 또는 DuckDuckGo 검색 스니펫에서 추적 가능해야 합니다. 이는 다음에 적용됩니다:
- 경쟁사 가격: 가져온 페이지 콘텐츠에서 그대로 추출
- "Contact Sales": 있는 그대로 기록, 절대 추정하거나 숫자로 대체하지 않음
- 티어 이름: 페이지에서 정확히 복사, 의역하지 않음
- 기능 목록: 페이지 콘텐츠에서 추출, 제품 지식에서 유추하지 않음
- 포지셔닝 관찰: 벤치마크 테이블 데이터에서만 도출
일반적인 실수
| 에이전트가 하려는 것 | 왜 잘못된지 |
|---|---|
| "Contact Sales"를 추정 가격으로 채우기 | 기업 가격을 추정하지 마세요. "Contact Sales"로 정확히 기록하세요. |
| 훈련 지식을 경쟁사 가격에 사용하기 | 모든 가격은 가져온 페이지 콘텐츠 또는 검색 스니펫에서 추적 가능해야 합니다. |
| 경쟁사 확인 단계 건너뛰기 | 항상 발견된 경쟁사를 보여주고 확인을 기다리세요. 잘못된 경쟁사 = 잘못된 벤치마크. |
| 벤치마크 데이터를 참조하지 않고 가격 추천하기 | 모든 가격 추천은 벤치마크 테이블의 특정 숫자를 인용해야 합니다. |
| 콘텐츠가 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 (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: 가져올 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'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: 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('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단계: 1단계 -- 경쟁사 발굴
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단계: 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'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가 있는 경우: 이는 가격 페이지가 차단되었거나 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\"]} (source: {r[\"source\"]}, quality: {r[\"data_quality\"]}) ===')
print(f'Pricing URL: {r[\"pricing_url\"]}')
print(r['content'][:4000])
print('---')
"
AI 지침: 각 경쟁사에 대해 위 콘텐츠에서 구조화된 가격 데이터를 추출하세요. references/extraction-guide.md를 따라 티어, 가격, 한도 및 CTA를 식별하는 방법을 확인하세요.
무-환각 규칙:
- 콘텐츠에서만 가격을 그대로 추출하세요. 가격이 콘텐츠에 없으면
null을 작성하세요. - "Contact Sales"를 있는 그대로 정확히 기록하세요. 추정된 숫자로 절대 대체하지 마세요.
data_quality: low는 데이터가 검색 스니펫에서 왔음을 의미합니다. 있는 것을 추출하지만 훈련 지식으로 간극을 채우지 마세요.- 콘텐츠에 없는 필드는
"not found in page data"를 작성하세요. - 연간 가격: 연간 총액과 함께 월간 등가 가격을 항상 기록하세요.
/tmp/pf-pricing-extracted.json에 쓰기:
python3 << 'PYEOF'
import json
# 작성: 아래 스키마를 따르는 경쟁사당 하나의 객체
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%" 또는 "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, # Contact Sales인 경우 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
# }
]
…