Google Places API : prospection B2B en Python + Lemlist
Constituez une base de prospects B2B qualifiés depuis Google Maps avec la Places API (New) de Google Cloud : configuration du projet, sécurisation de la clé API, recherche d'entreprises par type et par ville, pagination nextPageToken, export CSV prêt pour Lemlist ou HubSpot. Tutoriel pas à pas avec code Python prêt à copier, tarification de l'API, crédit gratuit de 200 $/mois (~6 000 requêtes Text Search) et stratégie multi-villes pour l'acquisition de leads locaux.
Enchaînez avec Lemlist — automatisation email B2B pour transformer ces prospects en cold-emails, Meta Ads pour l'acquisition B2C et la vue d'ensemble du programme acquisition.
Pourquoi Google Places API ?
L'objectif de cette section : comprendre en 30 secondes pourquoi Google Maps est probablement votre meilleure source gratuite de prospects B2B locaux.
Google Maps référence des millions d'entreprises avec leurs coordonnées (téléphone, site, adresse, note). L'API Google Places permet d'extraire ces données de manière structurée — fini le scraping fragile de pages web — pour constituer une base de prospects B2B qualifiés en quelques heures.
Cas d'usage typiques :
- Trouver tous les restaurants d'une ville pour leur vendre un logiciel de caisse
- Lister les agences immobilières d'une région pour proposer un service photo
- Identifier les salons de coiffure pour leur proposer un outil de réservation en ligne
À retenir : si votre cible a une présence physique (restaurant, salon, garage, agence), Google Places est presque toujours plus rentable que LinkedIn Sales Navigator pour la prospection locale.
Configuration de l'API
Trois étapes courtes (5 à 10 minutes) avant de pouvoir lancer votre première requête : projet Google Cloud, sécurisation de la clé, compréhension du modèle de tarification.
1. Créer un projet Google Cloud
- Rendez-vous sur Google Cloud Console
- Créez un nouveau projet
- Activez l'API Places API (New)
- Créez une clé API dans APIs & Services > Credentials
2. Sécuriser votre clé
# Ne jamais committer votre clé dans le code !
export GOOGLE_PLACES_API_KEY="votre-clé-ici"
Restrictions recommandées :
- Restreindre par API (Places API uniquement)
- Restreindre par IP ou referrer en production
- Définir un quota journalier pour éviter les dépassements de budget
Piège classique : un dépôt GitHub public avec une clé non restreinte = facture à 4 chiffres en quelques heures via abus.
3. Tarification
| Requête | Coût (par appel) |
|---|---|
| Text Search | 0,032 $ |
| Nearby Search | 0,032 $ |
| Place Details | 0,017 $ |
| Autocomplete | 0,00283 $ |
Google offre 200 $ de crédits mensuels gratuits, ce qui permet environ 6 000 recherches Text Search par mois.
Recherche d'entreprises par type et localisation
C'est le cœur du système : une fonction Python qui prend une requête + des coordonnées GPS et renvoie une liste structurée d'entreprises avec leur fiche complète.
Text Search (recommandé)
import requests
import json
API_KEY = "VOTRE_CLE_API"
BASE_URL = "https://places.googleapis.com/v1/places:searchText"
def rechercher_entreprises(requete: str, latitude: float, longitude: float, rayon_m: int = 5000) -> list[dict]:
"""
Recherche des entreprises via Google Places Text Search.
Args:
requete: ex. "restaurants italiens"
latitude: latitude du centre de recherche
longitude: longitude du centre de recherche
rayon_m: rayon de recherche en mètres (max 50000)
"""
headers = {
"Content-Type": "application/json",
"X-Goog-Api-Key": API_KEY,
"X-Goog-FieldMask": "places.displayName,places.formattedAddress,places.nationalPhoneNumber,places.websiteUri,places.googleMapsUri,places.rating,places.userRatingCount,places.businessStatus"
}
payload = {
"textQuery": requete,
"locationBias": {
"circle": {
"center": {"latitude": latitude, "longitude": longitude},
"radius": rayon_m
}
},
"languageCode": "fr"
}
response = requests.post(BASE_URL, headers=headers, json=payload)
data = response.json()
return data.get("places", [])
# Exemple : restaurants à Lyon
resultats = rechercher_entreprises("restaurants", 45.7640, 4.8357, 10000)
for place in resultats:
nom = place.get("displayName", {}).get("text", "N/A")
adresse = place.get("formattedAddress", "N/A")
tel = place.get("nationalPhoneNumber", "N/A")
site = place.get("websiteUri", "N/A")
note = place.get("rating", "N/A")
print(f"{nom} | {adresse} | {tel} | {site} | Note: {note}")
Pagination avec nextPageToken
L'API retourne 20 résultats par page. Pour en obtenir plus :
def rechercher_toutes_entreprises(requete: str, lat: float, lng: float, rayon_m: int = 5000, max_pages: int = 3) -> list[dict]:
"""Recherche paginée pour obtenir jusqu'à 60 résultats."""
tous_resultats = []
page_token = None
for page in range(max_pages):
headers = {
"Content-Type": "application/json",
"X-Goog-Api-Key": API_KEY,
"X-Goog-FieldMask": "places.displayName,places.formattedAddress,places.nationalPhoneNumber,places.websiteUri,places.rating,nextPageToken"
}
payload = {
"textQuery": requete,
"locationBias": {
"circle": {
"center": {"latitude": lat, "longitude": lng},
"radius": rayon_m
}
},
"languageCode": "fr",
"pageSize": 20
}
if page_token:
payload["pageToken"] = page_token
response = requests.post(BASE_URL, headers=headers, json=payload)
data = response.json()
resultats = data.get("places", [])
tous_resultats.extend(resultats)
page_token = data.get("nextPageToken")
if not page_token:
break
return tous_resultats
Enrichissement des données
Une fiche Places brute n'a souvent ni email ni horaires détaillés. Deux étapes pour la rendre exploitable en cold email : Place Details côté Google, puis extraction d'email côté site web.
Extraire les détails d'une entreprise
def obtenir_details(place_id: str) -> dict:
"""Obtient les détails complets d'un lieu."""
url = f"https://places.googleapis.com/v1/places/{place_id}"
headers = {
"X-Goog-Api-Key": API_KEY,
"X-Goog-FieldMask": "displayName,formattedAddress,nationalPhoneNumber,internationalPhoneNumber,websiteUri,googleMapsUri,rating,userRatingCount,businessStatus,types,regularOpeningHours"
}
response = requests.get(url, headers=headers)
return response.json()
Trouver l'email à partir du site web
Google Places ne fournit pas les emails. Il faut les extraire du site web :
import re
from bs4 import BeautifulSoup
def extraire_email_site(url: str) -> str | None:
"""Tente d'extraire un email depuis un site web."""
try:
response = requests.get(url, timeout=10, headers={
"User-Agent": "Mozilla/5.0"
})
# Chercher dans le HTML
emails = re.findall(
r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
response.text
)
# Filtrer les faux positifs courants
emails_valides = [
e for e in emails
if not e.endswith(('.png', '.jpg', '.gif', '.svg'))
and 'example' not in e
and 'wixpress' not in e
]
return emails_valides[0] if emails_valides else None
except Exception:
return None
Export vers CSV
import csv
def exporter_csv(entreprises: list[dict], fichier: str = "prospects.csv"):
"""Exporte les résultats en CSV pour import dans un CRM ou Lemlist."""
champs = ["nom", "adresse", "telephone", "site_web", "email", "note", "nb_avis"]
with open(fichier, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=champs)
writer.writeheader()
for e in entreprises:
site = e.get("websiteUri", "")
email = extraire_email_site(site) if site else ""
writer.writerow({
"nom": e.get("displayName", {}).get("text", ""),
"adresse": e.get("formattedAddress", ""),
"telephone": e.get("nationalPhoneNumber", ""),
"site_web": site,
"email": email,
"note": e.get("rating", ""),
"nb_avis": e.get("userRatingCount", "")
})
print(f"✓ {len(entreprises)} prospects exportés dans {fichier}")
Stratégie de scraping multi-villes
Une seule requête Places couvre un cercle (max 50 km de rayon). Pour couvrir un pays entier ou une grosse région, on découpe en plusieurs centres et on dédoublonne à la fin.
VILLES_FRANCE = [
{"nom": "Paris", "lat": 48.8566, "lng": 2.3522},
{"nom": "Lyon", "lat": 45.7640, "lng": 4.8357},
{"nom": "Marseille", "lat": 43.2965, "lng": 5.3698},
{"nom": "Toulouse", "lat": 43.6047, "lng": 1.4442},
{"nom": "Bordeaux", "lat": 44.8378, "lng": -0.5792},
{"nom": "Lille", "lat": 50.6292, "lng": 3.0573},
{"nom": "Nantes", "lat": 47.2184, "lng": -1.5536},
{"nom": "Strasbourg", "lat": 48.5734, "lng": 7.7521},
]
import time
def scraper_multi_villes(requete: str, villes: list[dict]) -> list[dict]:
"""Scrape des entreprises sur plusieurs villes."""
tous_prospects = []
for ville in villes:
print(f"Recherche à {ville['nom']}...")
resultats = rechercher_toutes_entreprises(
requete, ville["lat"], ville["lng"], rayon_m=15000
)
tous_prospects.extend(resultats)
time.sleep(1) # Respecter les rate limits
# Dédupliquer par nom + adresse
vus = set()
uniques = []
for p in tous_prospects:
cle = (
p.get("displayName", {}).get("text", ""),
p.get("formattedAddress", "")
)
if cle not in vus:
vus.add(cle)
uniques.append(p)
print(f"Total : {len(uniques)} prospects uniques sur {len(villes)} villes")
return uniques
Bonnes pratiques
- Respectez les quotas : surveillez votre consommation dans Google Cloud Console
- Cachez les résultats : stockez les résultats en base pour éviter les appels redondants
- Respectez les CGU : Google interdit le stockage massif des données Places sans affichage d'une carte
- Qualifiez vos prospects : filtrez par note, nombre d'avis et présence d'un site web
- Rate limiting : ajoutez des délais entre les requêtes (1-2 secondes)
Combien coûte la Google Places API en 2026 ?
La Google Places API (New) facture au volume de requêtes, mais Google offre un crédit gratuit de 200 $ par mois sur l'ensemble des produits Google Maps Platform. Concrètement, à 32 $ pour 1 000 appels Text Search, cela représente ≈ 6 000 requêtes gratuites par mois — largement suffisant pour constituer une base de quelques milliers de prospects B2B locaux. Au-delà, les tarifs sont dégressifs et la facturation est arrêtée si vous fixez un quota journalier dans la console Google Cloud, ce qui évite toute mauvaise surprise.
Quel langage de programmation utiliser pour la Places API ?
L'API Places est une API REST JSON : n'importe quel langage qui sait faire un POST HTTPS fonctionne (Python, Node.js, PHP, Go, Ruby, C#…). En pratique, Python avec la librairie requests est le choix le plus simple pour la prospection B2B : code court, parsing JSON natif, écosystème mature pour l'export CSV et l'enrichissement (pandas, BeautifulSoup pour scraper l'email sur les sites trouvés). Les exemples de ce chapitre sont en Python 3 prêts à copier-coller — comptez 30 minutes pour aller du compte Google Cloud à la première extraction CSV exploitable.
Comment récupérer l'email des prospects depuis Google Places ?
L'API Places ne renvoie pas l'email — seulement le nom, l'adresse, le téléphone, le site web et les avis. Pour obtenir l'email, la méthode la plus simple consiste à enchaîner avec un scraper léger sur le champ websiteUri retourné : vous parcourez la page d'accueil puis les pages /contact et /mentions-legales à la recherche d'un motif mailto: ou d'une regex email. Comptez 60-70 % de taux de récupération sur les TPE/PME françaises, et qualifiez votre base en éliminant les emails génériques (info@, contact@) si votre séquence Lemlist vise une persona précise (gérant, responsable marketing…).
À retenir — passez à l'action
- Commencez gratuit : les 200 $ de crédits mensuels suffisent à valider une niche avant tout investissement.
- Restreignez la clé dès la création (API + IP/referrer + quota journalier) — ne le faites jamais "plus tard".
- Collectez en 2 étapes : Text Search → Place Details, jamais tout d'un coup, pour minimiser le coût.
- Enrichissez l'email côté site web ; sans email, votre base ne vaut que pour le cold call.
- Dédoublonnez par (nom, adresse) dès la première extraction multi-villes — sinon votre Lemlist explose en doublons.
Prochaine étape : injecter ce CSV dans Lemlist pour automatiser la séquence de cold email — c'est le sujet du chapitre suivant.