Les outils de suivi de classement facturent 50 à 300 $/mois et se mettent à jour une fois par jour au mieux. Un moniteur SERP concurrentiel personnalisé vérifie exactement les mots-clés qui vous intéressent, à votre propre fréquence, et vous alerte sur les changements importants pour votre entreprise. Ce tutoriel construit un moniteur qui suit plusieurs concurrents sur des ensembles de mots-clés à 0,005 $/vérification, avec alertes Slack ou e-mail en cas de variations de position.
Prérequis
- Python 3.8+
- bibliothèque requests
- Une clé API Scavio depuis scavio.dev
- Domaines concurrents et mots-clés cibles
Parcours
Étape 1: Définir les concurrents et les mots-clés
Configurer la configuration de surveillance.
import os, requests, json, sqlite3
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
CONFIG = {
'competitors': ['serpapi.com', 'dataforseo.com', 'serper.dev', 'exa.ai', 'tavily.com'],
'keywords': [
'serp api', 'search api for developers', 'google search api python',
'web scraping api 2026', 'ai agent search api'
]
}
db = sqlite3.connect('serp_monitor.db')
db.execute('''CREATE TABLE IF NOT EXISTS rankings (
keyword TEXT, domain TEXT, position INTEGER,
checked_at TEXT, title TEXT
)''')
db.commit()
print(f'Monitoring {len(CONFIG["competitors"])} competitors across {len(CONFIG["keywords"])} keywords')
print(f'Daily cost: ${len(CONFIG["keywords"]) * 0.005:.3f}')Étape 2: Vérifier les classements pour tous les mots-clés
Effectuer une vérification SERP pour chaque mot-clé et enregistrer les positions des concurrents.
def check_rankings(keywords, competitors):
results = []
for kw in keywords:
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': kw, 'country_code': 'us'}).json()
organic = data.get('organic_results', [])
now = datetime.now().isoformat()
for r in organic[:20]:
domain = r.get('link', '').split('/')[2] if r.get('link') else ''
domain = domain.replace('www.', '')
if domain in competitors:
pos = r.get('position', 99)
db.execute('INSERT INTO rankings VALUES (?,?,?,?,?)',
(kw, domain, pos, now, r.get('title', '')[:80]))
results.append({'keyword': kw, 'domain': domain, 'position': pos})
db.commit()
print(f'Checked {len(keywords)} keywords. Cost: ${len(keywords) * 0.005:.3f}')
return results
ranks = check_rankings(CONFIG['keywords'], CONFIG['competitors'])
for r in ranks[:10]:
print(f' {r["keyword"]:30} | {r["domain"]:20} | #{r["position"]}')Étape 3: Détecter les changements de position
Comparer la vérification actuelle avec la précédente pour trouver les changements.
def detect_changes(keyword, domain, threshold=3):
rows = db.execute(
'SELECT position, checked_at FROM rankings WHERE keyword=? AND domain=? ORDER BY checked_at DESC LIMIT 2',
(keyword, domain)).fetchall()
if len(rows) < 2: return None
current, previous = rows[0][0], rows[1][0]
change = previous - current # positive = improved
if abs(change) >= threshold:
return {'keyword': keyword, 'domain': domain,
'previous': previous, 'current': current, 'change': change}
return None
def alert_changes(keywords, competitors, threshold=3):
alerts = []
for kw in keywords:
for comp in competitors:
change = detect_changes(kw, comp, threshold)
if change: alerts.append(change)
if alerts:
print(f'\n{len(alerts)} position changes detected:')
for a in alerts:
direction = 'UP' if a['change'] > 0 else 'DOWN'
print(f' {a["domain"]:20} | {a["keyword"]:25} | #{a["previous"]} -> #{a["current"]} ({direction} {abs(a["change"])})')
else:
print('No significant position changes.')
return alerts
alert_changes(CONFIG['keywords'], CONFIG['competitors'])Étape 4: Générer les données du tableau de bord concurrentiel
Construire une vue d'ensemble du paysage concurrentiel.
def dashboard(competitors, keywords):
print(f'\n{"Keyword":30} | ', end='')
for c in competitors[:5]: print(f'{c[:12]:12} | ', end='')
print()
print('-' * (32 + 15 * len(competitors[:5])))
for kw in keywords:
print(f'{kw[:30]:30} | ', end='')
for comp in competitors[:5]:
row = db.execute(
'SELECT position FROM rankings WHERE keyword=? AND domain=? ORDER BY checked_at DESC LIMIT 1',
(kw, comp)).fetchone()
pos = f'#{row[0]}' if row else '-'
print(f'{pos:12} | ', end='')
print()
total_checks = len(keywords)
print(f'\nMonthly cost estimate: ${total_checks * 0.005 * 30:.2f} (daily) or ${total_checks * 0.005 * 7:.2f} (weekly)')
# Run a check first, then display
check_rankings(CONFIG['keywords'], CONFIG['competitors'])
dashboard(CONFIG['competitors'], CONFIG['keywords'])Exemple Python
import os, requests
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def check(keyword, competitors):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
for r in data.get('organic_results', [])[:20]:
domain = r.get('link', '').split('/')[2].replace('www.', '')
if domain in competitors:
print(f'{keyword}: {domain} at #{r["position"]}')
check('serp api', ['serpapi.com', 'dataforseo.com', 'serper.dev'])Exemple JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function check(keyword, 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());
for (const r of (data.organic_results || []).slice(0, 20)) {
const domain = new URL(r.link).hostname.replace('www.', '');
if (competitors.includes(domain))
console.log(`${keyword}: ${domain} at #${r.position}`);
}
}
check('serp api', ['serpapi.com', 'dataforseo.com', 'serper.dev']).catch(console.error);Sortie attendue
Monitoring 5 competitors across 5 keywords
Daily cost: $0.025
Checked 5 keywords. Cost: $0.025
Keyword | serpapi.com | dataforseo.c | serper.dev | exa.ai | tavily.com |
-----------------------------------------------------------------------------------------------
serp api | #3 | #7 | #5 | #12 | #15 |
search api for developers | #4 | #8 | #6 | #9 | - |
google search api python | #2 | #5 | #4 | - | - |
web scraping api 2026 | #6 | #3 | #8 | - | - |
ai agent search api | #5 | - | #7 | #4 | #11 |
Monthly cost estimate: $3.75 (daily) or $0.88 (weekly)