L'analyse des écarts de mots-clés montre les requêtes pour lesquelles vos concurrents sont classés, mais pas vous. Les outils SEO facturent 100 $/mois ou plus pour cette fonctionnalité. Ce tutoriel construit la même analyse en utilisant des données SERP brutes à 0,005 $/mot-clé. Entrez votre domaine et ceux de vos concurrents, et obtenez une liste priorisée d'opportunités de contenu.
Prérequis
- Python 3.8+
- bibliothèque requests
- Une clé API Scavio depuis scavio.dev
- Votre domaine et 2-3 domaines concurrents
Parcours
Étape 1: Générer des candidats de mots-clés à partir des SERP concurrents
Trouver des mots-clés en vérifiant ce que les concurrents positionnent dans votre niche.
import os, requests, json
from collections import defaultdict
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
MY_DOMAIN = 'yourdomain.com'
COMPETITORS = ['competitor1.com', 'competitor2.com']
SEED_KEYWORDS = ['search api', 'serp api', 'web search api', 'mcp search', 'ai agent search']
def check_rankings(keyword, domains):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
organic = data.get('organic_results', [])
rankings = {}
for i, r in enumerate(organic):
link = r.get('link', '')
for domain in domains:
if domain in link and domain not in rankings:
rankings[domain] = i + 1
return rankings
results = []
for kw in SEED_KEYWORDS:
all_domains = [MY_DOMAIN] + COMPETITORS
rankings = check_rankings(kw, all_domains)
results.append({'keyword': kw, 'rankings': rankings})
my_pos = rankings.get(MY_DOMAIN, '-')
comp_pos = {c: rankings.get(c, '-') for c in COMPETITORS}
print(f' {kw:30} | You: {str(my_pos):5} | {", ".join(f"{c.split(".")[0]}: {v}" for c, v in comp_pos.items())}')
print(f'\nCost: ${len(SEED_KEYWORDS) * 0.005:.3f}')Étape 2: Identifier les écarts de mots-clés
Trouver des mots-clés pour lesquels les concurrents sont classés mais pas vous.
def find_gaps(results, my_domain, competitors):
gaps = []
for r in results:
kw = r['keyword']
rankings = r['rankings']
my_rank = rankings.get(my_domain)
comp_ranks = {c: rankings.get(c) for c in competitors if rankings.get(c)}
if not my_rank and comp_ranks:
best_comp = min(comp_ranks.items(), key=lambda x: x[1])
gaps.append({
'keyword': kw,
'best_competitor': best_comp[0],
'competitor_position': best_comp[1],
'num_competitors_ranking': len(comp_ranks),
'difficulty': 'easy' if best_comp[1] > 5 else 'medium' if best_comp[1] > 2 else 'hard'
})
gaps.sort(key=lambda g: g['competitor_position'])
print(f'\n=== Keyword Gaps ===')
print(f' You are missing from {len(gaps)} keywords where competitors rank:')
for g in gaps:
print(f' [{g["difficulty"]:6}] "{g["keyword"]}" - {g["best_competitor"]} at #{g["competitor_position"]}')
return gaps
gaps = find_gaps(results, MY_DOMAIN, COMPETITORS)Étape 3: Élargir les écarts avec des mots-clés connexes
Utiliser les données People Also Ask pour trouver plus d'opportunités d'écarts.
def expand_gaps(gaps):
expanded = []
for gap in gaps[:5]: # Expand top 5 gaps
kw = gap['keyword']
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': kw, 'country_code': 'us'}).json()
paa = data.get('people_also_ask', [])
related = [q.get('question', '') for q in paa if q.get('question')]
if related:
expanded.append({'seed': kw, 'related': related[:4]})
print(f'\n=== Expanded Gap Opportunities ===')
total_new = 0
for e in expanded:
print(f'\n "{e["seed"]}" -> {len(e["related"])} related keywords:')
for r in e['related']:
print(f' - {r[:55]}')
total_new += 1
print(f'\n New keyword opportunities: {total_new}')
print(f' Expansion cost: ${len(expanded) * 0.005:.3f}')
print(f' Total cost: ${(len(SEED_KEYWORDS) + len(expanded)) * 0.005:.3f}')
return expanded
expand_gaps(gaps)Exemple Python
import os, requests
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def gap_check(keyword, my_domain, competitors):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
organic = data.get('organic_results', [])
my_rank = next((i+1 for i, r in enumerate(organic) if my_domain in r.get('link', '')), None)
comp_ranks = {c: next((i+1 for i, r in enumerate(organic) if c in r.get('link', '')), None) for c in competitors}
is_gap = not my_rank and any(comp_ranks.values())
print(f'{"GAP" if is_gap else "OK":3} | {keyword:30} | You: {my_rank or "-"} | Comps: {comp_ranks}')
gap_check('search api python', 'scavio.dev', ['tavily.com'])
print('Cost: $0.005')Exemple JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function gapCheck(keyword, myDomain, competitors) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: keyword, country_code: 'us' })
}).then(r => r.json());
const organic = data.organic_results || [];
const myRank = organic.findIndex(r => r.link?.includes(myDomain));
const compRank = organic.findIndex(r => competitors.some(c => r.link?.includes(c)));
console.log(`${keyword}: You ${myRank >= 0 ? '#'+(myRank+1) : 'absent'} | Comp ${compRank >= 0 ? '#'+(compRank+1) : 'absent'}`);
}
await gapCheck('search api python', 'scavio.dev', ['tavily.com']);Sortie attendue
search api | You: 2 | competitor1: 4, competitor2: 7
serp api | You: - | competitor1: 3
web search api | You: 5 | competitor1: 2, competitor2: 6
mcp search | You: - | competitor1: 1, competitor2: 5
ai agent search | You: 3 | competitor1: -, competitor2: 8
Cost: $0.025
=== Keyword Gaps ===
You are missing from 2 keywords where competitors rank:
[hard ] "mcp search" - competitor1.com at #1
[medium] "serp api" - competitor1.com at #3
=== Expanded Gap Opportunities ===
"mcp search" -> 4 related keywords:
- What is MCP protocol for AI agents
- Best MCP search servers 2026
New keyword opportunities: 8