blog-cannibalization について
blog-cannibalizationは、検索キーワードが重複するブログ記事を見つけるスキルです。ローカルファイルの分析に加え、DataForSEOを使った順位データ分析と対処案の提示にも対応します。
主な機能
- 01ローカルでのキーワード重複分析
- 02DataForSEOによるSERP分析(任意)
- 03キーワードのクラスタリングと深刻度評価
- 04統合・差別化・canonical・監視の提案
- 05記事詳細付きクラスタレポート
活用シーン
- 01ブログディレクトリ内のキーワード重複調査
- 02公開URL間の順位キーワード比較
- 03SEO更新を優先する競合記事の特定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ infrasity-labs/ dev-gtm-claude-skills --skill blog-cannibalizationインストール後、Claude Code で/blog-cannibalizationを入力して読み込まれたか確認します。
詳細
ブログのカニバリゼーション - キーワード重複の検出
複数のブログ記事が同じ検索キーワードをめぐって競合している状況を検出します。2 つのモードがあります: ローカルのみの分析(デフォルト)と、SERP レベルのデータを使う DataForSEO API モードです。
2 つのモード
| モード | フラグ | 費用 | データソース |
|---|---|---|---|
| ローカル | (デフォルト) | 無料 | Grep/Read によるファイル内容の分析 |
| API | --api | 1 回あたり約 $0.01 | DataForSEO Page Intersection + Ranked Keywords |
ローカルモードは API キーなしで動作します。API モードでは、環境変数として設定した DataForSEO の認証情報が必要です:
DATAFORSEO_LOGIN と DATAFORSEO_PASSWORD。
ローカルモードのワークフロー
ステップ 1:ブログファイルをスキャンする
Glob を使って、対象ディレクトリ内のすべてのコンテンツファイルを検索します:
- パターン:
**/*.md、**/*.mdx、**/*.html node_modules/、.git/、drafts/内のファイルは除外します
ステップ 2:主要キーワードを抽出する
各ファイルを読み込み、次のキーワードの手がかりを抽出します:
- Title タグまたは H1 見出し(最も高い重み)
- H2 見出し(中程度の重み)
- 最初の段落(補助的な手がかり)
- frontmatter にある場合はメタディスクリプション
主要キーワードの抽出方法:
- タイトルと H1 をトークン化し、1-gram、2-gram、3-gram のフレーズに分割します
- タイトル、H2、最初の段落における出現頻度に基づいて、各フレーズをスコア化します
- スコアが最も高い 2~3 語のフレーズを主要キーワードとして選択します
- H2 見出しから副次キーワードを記録します
ステップ 3:類似度でクラスタリングする
次の照合ルールを優先順位順に適用し、記事をクラスタにまとめます:
- 完全一致 - 2 件以上の記事で主要キーワードが同一
- 語幹一致 - 同じ語根を持つ(例:「optimize」と「optimization」)
- 意味的な重複 - 2 つのキーワードが同じ検索意図を対象としていると Claude が判断する (例:「best CRM software」と「top CRM tools 2026」)
- 包含一致 - 一方のキーワードがもう一方を含む(例:「email marketing」 と「email marketing for startups」)
ステップ 4:スコアを付けてフラグを立てる
記事が 2 件以上ある各クラスタについて、深刻度を評価し、推奨事項を作成します。
ステップ 5:レポートを出力する
結果の表とクラスタごとの推奨事項を表示します。
API モードのワークフロー(DataForSEO)
--api フラグが必要です。WebFetch を使って DataForSEO のエンドポイントを呼び出します。
使用するエンドポイント
Page Intersection - 複数の URL がランクインしているキーワードを検索します:
POST https://api.dataforseo.com/v3/dataforseo_labs/google/page_intersection/live
Authorization: Basic <base64(login:password)>
{
"pages": {
"1": "https://example.com/post-a",
"2": "https://example.com/post-b"
},
"language_code": "en",
"location_code": 2840
}
費用:呼び出し 1 回あたり約 $0.01。順位、検索ボリューム、CPC を含む重複キーワードを返します。
Ranked Keywords - 1 つの URL がランクインしているすべてのキーワードを取得します:
POST https://api.dataforseo.com/v3/dataforseo_labs/google/ranked_keywords/live
{
"target": "https://example.com/post-a",
"language_code": "en",
"location_code": 2840
}
API 分析の手順
- ユーザーから公開済み URL をすべて収集します(またはサイトマップから取得します)
- 各 URL に対して Ranked Keywords を実行し、キーワードプロファイルを作成します
- キーワードクラスタを共有する URL の組み合わせに対して Page Intersection を実行します
- 以下の計算式を使って深刻度を算出します
- 検索ボリュームと順位のデータを含む拡張レポートを出力します
深刻度のスコアリング
重複の兆候に基づく 4 段階の深刻度レベル:
| レベル | 基準 | 対応の緊急度 |
|---|---|---|
| Critical | 同じ完全一致キーワードで、両方のページが上位 20 位以内 | 直ちに対応 |
| High | 同じキーワードクラスタで、一方のページが他方より上位 | 今週中 |
| Medium | 関連キーワードで SERP に部分的な重複がある | 今月中 |
| Low | 意味的には類似しているが、確認済みの検索意図は異なる | 監視 |
深刻度の計算式(API モード)
severity_score = overlap_count x avg_search_volume x (1 / position_gap)
ここで:
overlap_count= 共通するランキングキーワードの数avg_search_volume= 共通キーワードの月間検索ボリュームの平均position_gap= 平均ランキング順位の差の絶対値(最小値 1)
スコアが高いほど、カニバリゼーション問題への対応がより急務です。
深刻度のヒューリスティック(ローカルモード)
SERP データがない場合は、簡略化したスコアリングを使用します:
- Critical:記事間で主要キーワードが完全一致
- High:主要キーワードの語幹が一致、または H2 キーワードが 3 件以上共通
- Medium:主要キーワードに意味的な重複がある
- Low:包含一致のみ、または副次キーワードが共通
出力形式
概要テーブル
| Post A | Post B | Shared Keywords | Severity | Recommendation |
|--------|--------|-----------------|----------|----------------|
| /best-crm-tools | /top-crm-software | best crm, crm tools, crm software | Critical | MERGE |
| /email-tips | /email-marketing-guide | email marketing | High | DIFFERENTIATE |
| /seo-basics | /seo-for-beginners | seo basics, beginner seo | Critical | CANONICAL |
| /react-hooks | /react-state-mgmt | react, state | Low | NO ACTION |
クラスターごとの詳細
フラグが付いた各クラスターについて、以下を提示します。
- 両方の投稿のタイトルと URL
- 重複するキーワードの全リスト(API モードの場合は検索ボリュームも含む)
- どちらの投稿が優れているか(より包括的で、構成が優れているか)
- 具体的な推奨事項とその理由
推奨事項
カニバリゼーションクラスターごとに、次の 4 つの対応を選択できます。
統合
両方のページの内容が薄い場合や、同じ意図を同程度の深さで扱っている場合に選択します。
- 両方の優れた内容をまとめて、包括的な投稿を 1 つ作成します
- 劣る URL から統合後の投稿へ 301 リダイレクトを設定します
- いずれかの URL を指しているすべての内部リンクを維持します
差別化
ページの意図は異なるものの、キーワードのターゲティングが重複している場合に選択します。
- 劣る投稿の主要キーワードを、関連するロングテールキーワードに変更します
- タイトル、H1、メタディスクリプションを更新し、新たな焦点が反映されるようにします
- 2 つの投稿間に内部リンクを追加し、トピックが異なることを示します
正規化
一方の投稿が明らかに権威性を持ち、もう一方がその劣化版の重複である場合に選択します。
- 劣るページに
rel="canonical"を追加し、権威性の高いページを指定します - 劣るページに独自の価値がない場合は、noindex の設定を検討します
- 劣るページから権威性の高いページへリンクします
対応なし
表面的なキーワードの類似性があっても、検索意図が実際には異なる場合に選択します。
- 今後の監査に備えて、判断理由を記録します
- 四半期ごとにランキングを監視し、順位の変動を確認します
- いずれかの投稿の順位が下がった場合は、再評価します
エラー処理
- ブログファイルが見つからない場合: ディレクトリに .md、.mdx、または .html ファイルが存在しない場合は、「No blog files found in [directory]」と報告し、パスを確認するよう提案します
- DataForSEO の認証情報がない場合: API モードで認証情報が設定されていない場合は、自動的にローカルモードへ切り替え、ユーザーに通知します
- API のレート制限: DataForSEO には 1 分あたりのレート制限があります。429 レスポンスを受け取った場合は、待機して 1 回再試行します。それでも解決しない場合は、残りの URL の処理をローカルモードに切り替えます
- WebFetch の失敗: ソース URL にアクセスできない場合は、その URL をスキップし、レポートに「検証できません — ソースを利用できません」と記載します
- 投稿が 1 件のみのディレクトリ: ブログ投稿が 1 件しかない場合は、「Cannibalization analysis requires at least 2 posts」と報告し、正常に終了します