期限切れドメイン機会発見ツール は何をしますか?
特定のニッチに対する期限切れドメイン候補を評価します。トピック適合性、履歴活動レベル、履歴クリーン度、リダイレクト適合性に基づいてスコアリングします。人間によるレビューのための、保守的で説明可能なショートリストを出力します。
重要なルール: すべての推奨には、ポジティブな根拠 (why_selected) と注意すべき根拠 (why_risky) の両方を含める必要があります。スコアだけを説明なしで出力してはいけません。
デフォルトで保守的なルール: シグナルが不完全または矛盾している場合、信頼度を下げてください。曖昧な候補を強い機会として提示してはいけません。データ不足は信頼度を低下させ、決して引き上げてはいけません。
悪用防止ルール: 履歴トピックがターゲットニッチと一致しない場合、無関係なリダイレクト、PBN構築、またはドメインの転用を決して推奨してはいけません。完全な悪用防止ポリシーについては references/guardrails.md を参照してください。
ステップ 1: セットアップ確認
他の処理を行う前に環境を確認します。
curl と python3(または python)が利用可能であることを確認します:
curl --version > /dev/null 2>&1 && echo "curl: 利用可能" || echo "curl: なし"
python3 --version 2>/dev/null || python --version 2>/dev/null || echo "python: なし"
拡張ニッチ関連性スコアリングのためのオプションのLLM APIキーを確認します:
echo "LLM_API_KEY: ${LLM_API_KEY:+設定済み}"
curl または python がない場合:
停止します。ユーザーに伝える: 「このスキルには curl と Python 3.10+ が必要です。インストールしてから再試行してください。」
LLM_API_KEY が設定されていない場合:
続行します。スキルはルールベースのスコアリングのみを使用します(ドメイン文字列マッチング、Waybackタイトル分析、キーワード重複)。ユーザーに注意を促す: 「ルールベースのみのモードで実行中。拡張ニッチ関連性スコアリングのために LLM_API_KEY を設定してください。」
LLM_API_KEY が設定されている場合:
スキルはトピック関連性分析にLLM拡張スコアリングを使用します。これにより、ニッチ適合性のより深いコンテキスト評価が提供されます。
QA: スコアリングモード(llm拡張またはルールベースのみ)を明記し、ツールが利用可能であることを確認します。
ステップ 2: 入力収集
必要な入力とオプションの入力をユーザーから収集します。
必須:
target_niche(文字列): 評価するコアニッチ。例: "developer tools", "AI SaaS", "cybersecurity", "fintech"。
オプション(提供されていない場合のみ質問):
seed_keywords(配列): トピックマッチングを洗練するためのキーワード。提供されていない場合は、ニッチ名から3〜5個のキーワードを自動抽出します。candidate_domains(配列): 評価する特定のドメイン。提供されていない場合は、ユーザーにプロンプトを表示します。discovery_source(文字列): 候補のソース —manual、expireddomains-net、external-feedから選択。min_snapshots(整数): 最小履歴スナップショットしきい値。デフォルト: 10。max_risk_level(文字列):low、medium、またはhigh。リスクのある候補をどの程度積極的にフィルタリングするかを制御します。デフォルト:medium。intended_use(文字列):rebuild、redirect、またはeither。デフォルト:either。
candidate_domains が提供されなかった場合:
質問: 「評価する期限切れドメイン候補のリストを提供してください。以下の方法があります:
- ドメイン名を貼り付ける(1行に1つ、またはカンマ区切り)
- テキストファイルへのパスを提供する(1行に1ドメイン)
- 'example' と入力して、'developer tools' ニッチの組み込みデモセットを実行する」
ユーザーが 'example' と入力した場合: 以下のデモセットを使用:
devtoolsweekly.com
codeshipnews.io
stackforgeapp.com
quickseorank.net
bestcheaphosting247.com
cloudbuildpro.dev
reactwidgetlib.com
megadealsshop.xyz
すべての入力を収集した後、確認: 「ターゲットニッチ: [ニッチ]。評価数: [N] 候補ドメイン。スコアリングモード: [モード]。利用目的: [用途]。」
ステップ 3: 候補正規化
スコアリング前に候補リストをクリーンアップして検証します。
python3 -c "
import sys, re
domains = '''CANDIDATE_LIST_HERE'''.strip().split('\n')
seen = set()
valid = []
invalid = []
for d in domains:
d = d.strip().lower()
# Strip protocols and paths
d = re.sub(r'^https?://', '', d)
d = d.split('/')[0]
d = d.strip('.')
if not d:
continue
# Basic TLD validation
if '.' not in d or len(d) < 4:
invalid.append(d)
continue
# Deduplicate
if d in seen:
continue
seen.add(d)
valid.append(d)
print(f'有効な候補: {len(valid)}')
print(f'削除されたもの(無効/重複): {len(invalid)}')
for v in valid:
print(f' ✓ {v}')
for i in invalid:
print(f' ✗ {i} (無効な形式)')
"
CANDIDATE_LIST_HERE をステップ2の実際のドメインリストに置き換えます。
状態を表示: 「正規化後、[N] 件の有効な候補。[M] 件が削除されました(無効/重複)。」
有効な候補が0件の場合、停止してユーザーに伝える: 「有効なドメイン候補が見つかりませんでした。'example.com' 形式でドメイン名を提供してください。」
ステップ 4: シグナル収集
有効な各候補について、無料の公開ソースからシグナルを収集します。 これらのチェックを各ドメインに対して順次実行します。
4a: Wayback CDX API — 履歴スナップショット
Wayback Machine にすべての履歴スナップショットを問い合わせます。limit=100000 を使用し、from/to パラメータは意図的に省略しているため、CDX はドメインの全ライフタイムのスナップショットを返します。結果はタイムスタンプの昇順(古いものから新しいものへ)でソートされるため、first_capture と last_capture は正確です:
curl -s "https://web.archive.org/cdx/search/cdx?url=DOMAIN_HERE&output=json&fl=timestamp,statuscode&collapse=timestamp:6&limit=100000" \
| python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
if len(data) <= 1:
print(json.dumps({'domain': 'DOMAIN_HERE', 'snapshots': 0, 'first_capture': None, 'last_capture': None, 'status_codes': {}, 'years_active': 0}))
else:
rows = data[1:] # skip header row
timestamps = [r[0] for r in rows] # already ascending (oldest first)
statuses = [r[1] for r in rows]
status_counts = {}
for s in statuses:
status_counts[s] = status_counts.get(s, 0) + 1
first_year = int(timestamps[0][:4])
last_year = int(timestamps[-1][:4])
print(json.dumps({
'domain': 'DOMAIN_HERE',
'snapshots': len(rows),
'first_capture': timestamps[0],
'last_capture': timestamps[-1],
'status_codes': status_counts,
'years_active': last_year - first_year + 1
}))
except:
print(json.dumps({'domain': 'DOMAIN_HERE', 'snapshots': 0, 'error': 'wayback_api_failed'}))
"
レート制限: サービスへの負荷を考慮し、Wayback API の呼び出し間隔は2秒空けてください。
4b: Wayback コンテンツサンプリング — 履歴ページタイトル
スナップショットが1件以上の候補について、最新のスナップショットを取得してページタイトルを抽出します(トピック関連性スコアリングに使用):
curl -s -L "https://web.archive.org/web/LATEST_TIMESTAMP/http://DOMAIN_HERE" \
| python3 -c "
import sys, re
html = sys.stdin.read()[:50000]
title_match = re.search(r'<title[^>]*>(.*?)</title>', html, re.IGNORECASE | re.DOTALL)
title = title_match.group(1).strip() if title_match else 'タイトルなし'
# Extract meta description too
meta_match = re.search(r'<meta[^>]*name=[\"']description[\"'][^>]*content=[\"'](.*?)[\"']', html, re.IGNORECASE)
desc = meta_match.group(1).strip() if meta_match else '説明なし'
print(f'タイトル: {title}')
print(f'説明: {desc}')
"
LATEST_TIMESTAMP をステップ4aの最新タイムスタンプに置き換えます。
4c: RDAP ルックアップ — 登録ステータス
クロスプラットフォームのHTTPベースRDAP標準を使用します(OS依存のWHOISを置き換えます)。RDAPからのHTTP 404は、ドメインが登録されていないこと(つまり、真に利用可能または追跡されていないこと)を意味します。これはネットワーク障害とは区別されます。両方のケースを明示的に処理します:
python3 -c "
import urllib.request, urllib.error, json
domain = 'DOMAIN_HERE'
try:
req = urllib.request.Request(
f'https://rdap.org/domain/{domain}',
headers={'User-Agent': 'Mozilla/5.0'}
)
with urllib.request.urlopen(req, timeout=10) as response:
data = json.loads(response.read().decode())
registrar = '不明'
created = '不明'
for entity in data.get('entities', []):
if 'registrar' in entity.get('roles', []):
try:
registrar = entity.get('vcardArray', [[]])[1][0][3]
except Exception:
pass
for event in data.get('events', []):
if event.get('eventAction') == 'registration':
created = event.get('eventDate', '不明')
print(json.dumps({
'domain': domain,
'status': 'registered',
'registrar': registrar,
'created': created
}))
except urllib.error.HTTPError as e:
if e.code == 404:
# Domain has no RDAP object — likely unregistered or not in RDAP coverage
print(json.dumps({'domain': domain, 'status': 'unregistered_or_no_rdap_object'}))
else:
print(json.dumps({'domain': domain, 'error': f'rdap_http_error_{e.code}'}))
except Exception:
print(json.dumps({'domain': domain, 'error': 'rdap_lookup_failed'}))
"
4d: ドメイン文字列分析 — キーワードマッチング
ドメイン名とターゲットニッチ/シードキーワード間のキーワード重複をスコアリングします:
python3 -c "
import re, json
domain = 'DOMAIN_HERE'
niche = 'NICHE_HERE'
seeds = SEEDS_JSON_HERE # e.g., ['devops', 'ci/cd', 'code editor']
# Extract words from domain
domain_base = domain.rsplit('.', 1)[0] # remove TLD
domain_words = re.split(r'[-_.]', domain_base.lower())
# Check niche words
niche_words = niche.lower().split()
all_keywords = set(niche_words + [s.lower() for s in seeds])
matches = [w for w in domain_words if any(kw in w or w in kw for kw in all_keywords)]
match_ratio = len(matches) / max(len(domain_words), 1)
print(json.dumps({
'domain': domain,
'domain_words': domain_words,
'keyword_matches': matches,
'match_ratio': round(match_ratio, 2)
}))
"
4e: Gemini LLM ニッチ関連性評価(LLM_API_KEYが設定されている場合)
LLM APIキーが設定されている場合、すべての候補と収集されたシグナルをバッチ処理し、コンテキストに基づいたニッチ関連性評価を求めます。
注: 以下のリクエスト/レスポンス形式は Gemini API (generateContent 形式) を使用しています。変更なしではOpenAIスタイルのエンドポイントと互換性がありません。別のプロバイダーを使用する場合は、JSONボディとレスポンス解析を適応させる必要があります。
cat > /tmp/domain-relevance-request.json << 'ENDJSON'
{
"system_instruction": {
"parts": [{
"text": "あなたはSEOリサーチアナリストです。提供された各期限切れドメイン候補について、指定されたターゲットニッチに対するトピック関連性を評価してください。ドメイン名、履歴ページタイトル、メタ説明を考慮してください。各ドメインについて、以下を含むJSONオブジェクトを出力してください: domain(文字列)、relevance_score(整数 1〜10)、relevance_rationale(スコアを説明する一文)、redirect_plausibility(整数 1〜10)、redirect_rationale(一文)。JSON配列のみを出力してください。前後のコメントは不要です。"
}]
},
"contents": [{
"parts": [{
"text": "DOMAIN_SIGNALS_AND_NICHE_CONTEXT_HERE"
}]
}],
"generationConfig": {
"temperature": 0.2,
"maxOutputTokens": 2048
}
}
ENDJSON
DOMAIN_SIGNALS_AND_NICHE_CONTEXT_HERE を以下の内容に置き換えます:
- ターゲットニッチとシードキーワード
- 各候補について: ドメイン名、履歴タイトル、説明、キーワードマッチデータ
リクエストを Gemini API に送信:
curl -s -X POST \
"${LLM_API_ENDPOINT:-https://generativelanguage.googleapis.com/v1beta}/models/${LLM_MODEL:-gemini-2.0-flash}:generateContent?key=$LLM_API_KEY" \
-H "Content-Type: application/json" \
-d @/tmp/domain-relevance-request.json \
| python3 -c "
import sys, json
try:
d = json.load(sys.stdin)
text = d['candidates'][0]['content']['parts'][0]['text']
print(text)
except (KeyError, IndexError, json.JSONDecodeError) as e:
print(json.dumps({'error': 'llm_response_parse_failed', 'detail': str(e)}))
"
LLM呼び出しまたはレスポンス解析が失敗した場合、エラーをログに記録し、ルールベースのスコアリングのみで続行します。ワークフローを停止しないでください。
すべてのシグナル収集後、状態を表示: 「シグナル収集完了: [N] 候補。[M] 件のWaybackヒット、[K] 件のRDAPルックアップ成功。」
ステップ 5: スコアリングと分類
完全なスコアリングフレームワークについては references/scoring-model.md を参照してください。
各候補について、6つの次元にわたってスコアを計算します:
-
トピック関連性 (0〜30): ドメインキーワードマッチ比率、履歴タイトル/説明分析、および(利用可能な場合)LLM関連性スコアを組み合わせます。LLMなし: キーワードマッチ比率 × 15 + タイトルキーワード重複 × 15。LLMあり: LLM relevance_score × 3。
-
履歴活動レベル (0〜25): Waybackスナップショットの多様性と頻度に基づきます。複数年にわたって一貫してキャプチャされたスナップショットが多いほど、高い持続的活動と推定される正当性を示します。
-
履歴コンテンツ品質 (0〜15): 履歴ページタイトルとメタ説明分析から導出され、自然な表現とキーワードスタッフィングをチェックします。LLMなし: 正確一致密度によって調整された基本スコア 8/15。
-
履歴クリーン度 (0〜15): Waybackスナップショット数、活動年数、ステータスコードの一貫性、およびパーキングページ指標の欠如に基づきます。
-
リダイレクト適合性 (0〜10): 履歴コンテンツとターゲットニッチ間のトピックの継続性に基づきます。利用可能な場合はLLM redirect_plausibilityスコアを使用し、それ以外の場合はキーワード重複比率を使用します。
-
シグナル完全性 (0〜5): 使用可能なデータを返したデータソースの数をカウントします(Wayback、RDAP、ドメイン分析、LLM(設定されている場合))。
計算:
opportunity_score= すべての次元スコアの合計 (0〜100)confidence= 強いデータを持つ次元の数に基づく(scoring-model.md を参照)recommended_action= スコア + 信頼度 + リスクフラグに基づく(ステップ6を参照)
ステップ 6: リスクフラグとフィルタリング
完全なフラグ定義については references/risk-flags.md を参照してください。
各候補にリスクフラグを適用します:
| チェック項目 | 適用フラグ |
|---|---|
| 履歴トピックの重複がターゲットニッチと30%未満 | low_topic_alignment |
| スナップショット数が最小しきい値を下回る | low_history_depth |
| 過去1年間のスナップショットがない | recent_history_gap |
| 主なステータスコードが4xxまたは5xx(元のコンテンツは削除された可能性が高い) | content_gone |
| 全スナップショットのうち90%以上がHTTP 200以外(パーキング/エラーの可能性) | parked_or_broken |
| 直近のキャプチャされたタイトルに "buy this domain" または "parked free" が含まれている | parking_page_detected |
| RDAPが登録ステータスを返した(つまり、ドメインが現在登録されている) | still_registered |
max_risk_level が low に設定され、少なくとも1つのリスクフラグが concerning カテゴリにある | blocked_by_risk_threshold |
フィルタリングルール:
- 自動フィルタリングは
max_risk_levelに従う:low: 1つ以上のconcerningフラグがある候補をブロックmedium: 2つ以上のconcerningフラグがある候補をブロックhigh: すべての候補を保持、ただしすべてのフラグを表示
redまたはcriticalカテゴリのどのフラグも、ブロックする原因となる。
ステップ 7: 初期出力(テーブル)
フィルタリング後、各候補に対してテーブル形式の情報を出力します:
+---------------------------+------+-------------+------------+----------------------------------------------+
| ドメイン | スコア | 信頼度 | 推奨アクション | 主な理由 |
+---------------------------+------+-------------+------------+----------------------------------------------+
| devtoolsweekly.com | 78 | high | 確認推奨 | 強力なトピック一致、6年分のコンテンツ履歴 |
| codeshipnews.io | 62 | medium | 注意して確認 | 適度なトピック一致、最近のギャップあり |
| stackforgeapp.com | 45 | low | 非推奨 | 低いトピック一致、履歴なし |
+---------------------------+------+-------------+------------+----------------------------------------------+
注意: このテーブルはクライアント画面の幅に合わせて動的な列幅でフォーマットしてください。
ステップ 8: 詳細出力(Markdown)
各候補の詳細な説明を提供します:
1. devtoolsweekly.com
- 機会スコア: 78/100 (信頼度: high)
- 推奨アクション: 確認推奨
- トピック関連性 (25/30): ドメイン文字列は「devtools」と「weekly」をターゲットにしており、開発者ツールのニュースレターニッチと強く一致。履歴タイトル: "DevTools Weekly - 開発者のためのニュースレター"。キーワードマッチ率: 0.67。
- 履歴活動レベル (20/25): Wayback Machine に 2,342 件のスナップショットあり。2018年〜2024年の範囲。毎月安定したキャプチャあり。
- 履歴コンテンツ品質 (12/15): 明確なニュースレター形式。高品質なライティング。自然な言語。キーワードスタッフィングは確認されず。
- 履歴クリーン度 (12/15): 主なHTTPステータス: 200 (92%)。パーキングページ指標は確認されず。
- リダイレクト適合性 (7/10): トピックは毎週の開発者ツールダイジェストに強く関連。同等のサイトへのリダイレクトに適しています。
- シグナル完全性 (2/5): Waybackデータは良好、RDAPからは unregistered を返された(Waybackに関連するシグナルは保持)。
なぜ選ばれたか: 開発者ツールのニッチとの強力なトピック一致、広範な履歴コンテンツ、一貫したキャプチャ。
なぜリスクがあるか: ドメインは現在RDAPに登録されていないようです — 別の当事者によってすでに取得されている可能性があります。購入前に登録ステータスを確認してください。
...(各候補について同様の形式)
ステップ 9: 結論と推奨事項
最終的な要約を提供します:
=== 期限切れドメイン評価: 要約 ===
ターゲットニッチ: developer tools
評価候補数: 24
フィルタリング後: 5
上位推奨 (確認推奨):
1. devtoolsweekly.com (78/100, high信頼度)
2. reactwidgetlib.com (71/100, high信頼度)
3. cloudbuildpro.dev (65/100, medium信頼度)
確認候補 (注意して確認):
1. codeshipnews.io (62/100, medium信頼度)
2. stackforgeapp.com (58/100, low信頼度)
今後のステップ:
1. 上位候補のバックリンクプロファイルを確認 (Ahrefs / Majestic)
2. 閲覧者の意図を尊重するリダイレクト戦略を検証
3. 購入前にWayback Machineで削除されたコンテンツの復元可能性を評価
4. [推奨されるドメインが購入された場合] Google Search Console でサイト移動プロパティを設定
=== 期限切れドメイン評価: リスクと注意事項 ===
- すべての期限切れドメインは入札または取得される可能性があります。決定する前にリアルタイムの可用性を確認してください。
- 過去の検索エンジンのペナルティはWayback Machineデータには表示されません。Google Search Console の過去データは公開されていません。取得後に Search Console を監視してください。
- [ドメインを既存サイトにリダイレクトする場合] リダイレクトされたドメインの被リンクプロファイルがリダイレクト先のサイトにとって健全であることを確認してください。
エラーハンドリング
共通エラーケース
| エラー | ハンドリング |
|---|---|
| Wayback APIがタイムアウト(30秒以上) | ドメインの timeouts をログに記録し、signal_completeness を減点。残りのドメインは続行。 |
| RDAPルックアップが失敗 | status: 'rdap_lookup_failed' をログに記録し、signal_completeness を減点。このエラーを理由に候補をブロックしないでください。RDAPは単なる確認です。 |
| すべてのデータソースが失敗 | candidate を insufficient_signals としてマーク。スコアを 0 に設定。risk_flags に no_signals を追加。 |
ユーザーが無効な max_risk_level を指定 | デフォルトを medium に設定し、ユーザーに通知: 「無効な max_risk_level です。'medium' を使用します。」 |
ユーザーが無効な intended_use を指定 | デフォルトを either に設定し、ユーザーに通知: 「無効な intended_use です。'either' を使用します。」 |