Une page classée n°1 peut obtenir zéro clic si un aperçu IA répond à la requête au-dessus d'elle. La surveillance des surfaces de recherche suit chaque fonctionnalité SERP : aperçus IA, boîtes PAA, extraits, panneaux de connaissances et packs locaux. Lorsque les fonctionnalités changent, votre visibilité change même si le classement reste le même. Ce tutoriel construit un moniteur de surface à $0.005/mot-clé.
Prérequis
- Python 3.8+
- bibliothèque requests
- Une clé API Scavio depuis scavio.dev
- Mots-clés à surveiller
Parcours
Étape 1: Capturer les surfaces SERP complètes
Analyser tous les types de fonctionnalités pour chaque mot-clé.
import os, requests, json
from datetime import date
API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
DOMAIN = 'mysite.com'
KEYWORDS = ['serp api python', 'web scraping api 2026', 'tiktok data api']
def capture(keyword):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': keyword, 'country_code': 'us'}).json()
features = {}
if data.get('answer_box'): features['answer_box'] = True
if data.get('ai_overview'): features['ai_overview'] = True
if data.get('related_questions'): features['paa'] = len(data['related_questions'])
if data.get('knowledge_graph'): features['kg'] = True
pos = next((r['position'] for r in data.get('organic_results', []) if DOMAIN in r.get('link', '')), None)
return {'keyword': keyword, 'date': date.today().isoformat(), 'features': features, 'position': pos}Étape 2: Comparer avec les instantanés précédents
Détecter l'apparition ou la disparition des fonctionnalités.
def detect_changes(current, previous):
if not previous: return ['NEW: first capture']
changes = []
curr_f = set(current['features'])
prev_f = set(previous.get('features', {}))
for f in curr_f - prev_f: changes.append(f'ADDED: {f}')
for f in prev_f - curr_f: changes.append(f'REMOVED: {f}')
cp, pp = current.get('position'), previous.get('position')
if cp and pp and cp != pp: changes.append(f'RANK: {pp} -> {cp}')
return changesÉtape 3: Lancer le moniteur
Capturer, comparer et enregistrer l'état.
def run_monitor():
try:
with open('surface.json') as f: prev = {e['keyword']: e for line in f for e in [json.loads(line)]}
except FileNotFoundError: prev = {}
surfaces = []
for kw in KEYWORDS:
s = capture(kw)
surfaces.append(s)
changes = detect_changes(s, prev.get(kw))
feats = ', '.join(s['features']) or 'organic only'
print(f' {kw}: pos={s["position"] or "N/A"}, [{feats}]')
for c in changes: print(f' {c}')
with open('surface.json', 'w') as f:
for s in surfaces: f.write(json.dumps(s) + '\n')
print(f'Cost: ${len(KEYWORDS) * 0.005:.3f}')
run_monitor()Étape 4: Calculer le score de visibilité
Estimer l'impact sur le CTR à partir des fonctionnalités SERP.
def visibility(surface):
pos = surface.get('position')
if not pos: return 0.0
base = {1: 0.30, 2: 0.15, 3: 0.10, 4: 0.07, 5: 0.05}.get(pos, 0.02)
if 'ai_overview' in surface.get('features', {}): base *= 0.5
if 'answer_box' in surface.get('features', {}): base *= 0.7
return round(base, 4)
for kw in KEYWORDS:
s = capture(kw)
v = visibility(s)
print(f' {kw}: pos={s["position"]}, visibility={v:.2%}')Exemple Python
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
def check(kw, domain):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': kw, 'country_code': 'us'}).json()
features = [k for k in ['answer_box', 'ai_overview', 'related_questions', 'knowledge_graph'] if data.get(k)]
pos = next((r['position'] for r in data.get('organic_results', []) if domain in r.get('link', '')), None)
print(f'{kw}: pos={pos or "N/A"}, features={features}')
check('serp api python', 'mysite.com')Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const H = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' };
async function check(kw, domain) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: H, body: JSON.stringify({ query: kw, country_code: 'us' })
}).then(r => r.json());
const features = ['answer_box', 'ai_overview', 'related_questions'].filter(k => data[k]);
const match = (data.organic_results || []).find(r => r.link.includes(domain));
console.log(`${kw}: pos=${match?.position||'N/A'}, features=[${features}]`);
}
check('serp api python', 'mysite.com').catch(console.error);Sortie attendue
serp api python: pos=4, [paa]
web scraping api 2026: pos=7, [ai_overview, paa, answer_box]
ADDED: ai_overview
RANK: 5 -> 7
tiktok data api: pos=2, [paa]
Cost: $0.015