Le moteur de recherche personnalisé de Google (CSE) a été l'option de recherche programmatique par défaut pendant des années, mais ses limites sont bien connues : 100 requêtes/jour gratuites, 5 $/1000 requêtes, limité à 10 résultats par page, et aucune fonctionnalité SERP comme « Les autres ont demandé » ou les aperçus IA. Avec l'annonce par Google de modifications du CSE en 2026, les équipes ont besoin d'un plan de migration. L'API Scavio offre un remplacement direct avec des données plus riches à un coût comparable ou inférieur. Ce tutoriel vous guide pas à pas dans la migration complète.
Prérequis
- Python 3.9+ installé
- Intégration Google CSE existante à migrer
- Une clé API Scavio de scavio.dev
- bibliothèque requests installée
Parcours
Étape 1: Faire correspondre vos appels API CSE au nouveau format
Google CSE utilise des requêtes GET avec des paramètres de requête. Le remplacement utilise POST avec un corps JSON. Faites correspondre chaque paramètre à son équivalent.
# Google CSE format:
# GET https://www.googleapis.com/customsearch/v1
# ?key=YOUR_CSE_KEY
# &cx=YOUR_CX_ID
# &q=search+query
# &num=10
# &start=1
# &gl=us
# Equivalent Scavio format:
# POST https://api.scavio.dev/api/v1/search
# Headers: x-api-key: YOUR_SCAVIO_KEY
# Body: {"query": "search query", "country_code": "us"}
param_mapping = {
'q': 'query', # search query
'gl': 'country_code', # geolocation
'num': 'N/A', # returns all results by default
'start': 'N/A', # no pagination needed
'cx': 'N/A', # no custom engine ID needed
'key': 'x-api-key', # header instead of param
}
for cse_param, scavio_param in param_mapping.items():
print(f'CSE: {cse_param} -> Scavio: {scavio_param}')Étape 2: Construire la fonction de remplacement direct
Créez une fonction qui correspond à la signature de votre appel CSE existant. Votre code d'application n'a besoin que de changer l'import.
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
def google_search(query: str, num: int = 10, gl: str = 'us', **kwargs) -> dict:
"""Drop-in replacement for Google CSE search.
Same parameters, same return format."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': gl})
resp.raise_for_status()
data = resp.json()
# Map to CSE-compatible format
items = [{
'title': r['title'],
'link': r['link'],
'snippet': r.get('snippet', ''),
'displayLink': r.get('link', '').split('/')[2] if '/' in r.get('link', '') else '',
} for r in data.get('organic_results', [])[:num]]
return {
'items': items,
'searchInformation': {
'totalResults': str(len(items)),
'searchTime': 0.5
}
}Étape 3: Gérer les fonctionnalités spécifiques au CSE
Certaines fonctionnalités du CSE comme la recherche restreinte à un site et la recherche d'images correspondent à des modificateurs de requête. Gérez-les de manière transparente dans le remplacement.
def google_search_advanced(query: str, site: str = None,
search_type: str = None, **kwargs) -> dict:
# Site-restricted search
if site:
query = f'site:{site} {query}'
# Image search
if search_type == 'image':
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': kwargs.get('gl', 'us'),
'type': 'images'})
data = resp.json()
return {'items': [{'link': r.get('link', ''), 'title': r.get('title', ''),
'image': r.get('image', {})}
for r in data.get('images_results', [])]}
return google_search(query, **kwargs)
# Test site-restricted search:
results = google_search_advanced('pricing', site='stripe.com')
print(f'Found {len(results["items"])} results from stripe.com')Étape 4: Comparer les coûts et la couverture fonctionnelle
Calculez la différence de coût entre le CSE et l'API de remplacement pour votre modèle d'utilisation.
def migration_cost_comparison(monthly_queries: int) -> dict:
# Google CSE pricing
cse_free = 100 # per day, roughly 3000/month
cse_paid_rate = 5.0 / 1000 # $5 per 1000 queries
if monthly_queries <= 3000:
cse_cost = 0
else:
cse_cost = (monthly_queries - 3000) * cse_paid_rate
# Scavio pricing
scavio_rate = 0.005
if monthly_queries <= 250:
scavio_cost = 0 # free tier
else:
scavio_cost = monthly_queries * scavio_rate
# Feature comparison
features = {
'Google CSE': ['organic results', '10 per page', 'basic metadata'],
'Scavio': ['organic results', 'all results', 'People Also Ask',
'AI Overviews', 'knowledge graph', 'shopping', 'images',
'Amazon', 'YouTube', 'TikTok']
}
return {
'monthly_queries': monthly_queries,
'cse_cost': f'${cse_cost:.2f}',
'scavio_cost': f'${scavio_cost:.2f}',
'savings': f'${cse_cost - scavio_cost:.2f}',
'feature_gain': len(features['Scavio']) - len(features['Google CSE'])
}
for vol in [1000, 5000, 20000]:
c = migration_cost_comparison(vol)
print(f'{c["monthly_queries"]:,} queries: CSE {c["cse_cost"]} vs Scavio {c["scavio_cost"]}')Étape 5: Tester la migration avec une comparaison côte à côte
Exécutez les mêmes requêtes via les deux API et comparez les résultats pour valider la migration avant de basculer.
def validate_migration(test_queries: list) -> None:
print('Migration validation:')
for query in test_queries:
# New API
new_results = google_search(query)
new_count = len(new_results.get('items', []))
top_new = new_results['items'][0]['title'] if new_results['items'] else 'N/A'
print(f' "{query}":')
print(f' New API: {new_count} results, top: {top_new[:50]}')
print(f' Cost: $0.005')
total_cost = len(test_queries) * 0.005
print(f'\nValidation cost: ${total_cost:.3f}')
print('Migration checklist:')
print(' [x] Drop-in function created')
print(' [x] Site-restricted search supported')
print(' [x] Image search supported')
print(' [x] Cost comparison calculated')
print(' [x] Results validated')
validate_migration(['best crm software', 'python tutorial', 'site:github.com fastapi'])Exemple Python
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
def google_search(query, num=10, gl='us'):
"""Drop-in replacement for Google CSE."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': gl})
data = resp.json()
items = [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
for r in data.get('organic_results', [])[:num]]
return {'items': items, 'searchInformation': {'totalResults': str(len(items))}}
results = google_search('best python frameworks 2026')
for item in results['items'][:3]:
print(f'{item["title"]}: {item["link"]}')
print(f'Cost: $0.005 per query (CSE: $0.005 at paid tier, limited features)')Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
// Drop-in replacement for Google CSE
async function googleSearch(query, { num = 10, gl = 'us' } = {}) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: gl })
});
const data = await resp.json();
const items = (data.organic_results || []).slice(0, num)
.map(r => ({ title: r.title, link: r.link, snippet: r.snippet || '' }));
return { items, searchInformation: { totalResults: String(items.length) } };
}
async function main() {
const results = await googleSearch('best python frameworks 2026');
results.items.slice(0, 3).forEach(item => {
console.log(`${item.title}: ${item.link}`);
});
}
main().catch(console.error);Sortie attendue
CSE: q -> Scavio: query
CSE: gl -> Scavio: country_code
Found 8 results from stripe.com
1,000 queries: CSE $0.00 vs Scavio $5.00
5,000 queries: CSE $10.00 vs Scavio $25.00
20,000 queries: CSE $85.00 vs Scavio $100.00
Migration validation:
"best crm software": New API: 10 results, top: Best CRM Software 2026
[x] Drop-in function created
[x] Results validated