Comment Scraper les Avis Google avec Python — Guide Complet 2025
Les avis Google sont une mine d'or de retours clients, mais collecter manuellement des milliers d'entre eux ? C'est inefficace et peu pratique.
Avec Python, vous pouvez automatiser l'ensemble du processus d'extraction et rassembler des milliers d'avis en quelques heures. Ce guide vous accompagne à travers tout — de la configuration de base aux scrapers prêts pour la production qui gèrent les défenses anti-scraping de Google.
À la fin, vous comprendrez comment construire des scrapers d'avis fiables, éviter la détection et extraire des informations clients exploitables à grande échelle.
Qu'est-ce que le Scraping des Avis Google ?
Le scraping des avis Google est l'extraction automatisée des données de retour client à partir de Google Maps et des profils Google Business en utilisant des scripts Python.
Lorsque vous scrapez les avis Google, vous capturez :
- Évaluations par étoiles (1 à 5 étoiles)
- Texte de l'avis (commentaires complets des clients)
- Noms et profils des évaluateurs
- Dates et horodatages des avis
- Réponses des entreprises (si le propriétaire a répondu)
- Nombre de votes utiles
Contrairement à l'API officielle de Google — qui est coûteuse et fortement limitée en termes de taux — le scraping vous donne accès à tous les avis disponibles sans quotas ni restrictions.
Pourquoi Scraper au Lieu d'Utiliser l'API de Google ?
L'API officielle de Google Places pour les avis a de sérieuses limitations :
| Fonctionnalité | API Officielle | Web Scraping |
|---|---|---|
| Avis par demande | ~10 (récents seulement) | Tous disponibles |
| Coût | 7 $ par 1 000 demandes | Gratuit à faible coût |
| Limites de taux | 100 demandes/seconde max | Configurables |
| Avis des concurrents | ❌ Non | ✅ Oui |
| Complexité de configuration | Modérée (authentification) | Plus élevée (technique) |
Pour l'analyse concurrentielle, la recherche de marché ou la collecte de données à grande échelle, le scraping est le choix pratique.
Pourquoi Python est le Meilleur Langage pour Cette Tâche
Python domine le web scraping pour trois raisons principales :
1. Écosystème de Scraping Riche
Python dispose de bibliothèques spécialement conçues pour le web scraping :
- Playwright — Automatisation de navigateur moderne et rapide
- Selenium — Éprouvé, compatibilité maximale
- BeautifulSoup — Analyse HTML légère
- Scrapy — Framework de scraping de niveau entreprise
- Pandas — Manipulation et exportation de données
Vous pouvez passer de HTML brut à CSV nettoyé en un seul script.
2. Exécution de JavaScript
Les avis Google se chargent dynamiquement via JavaScript, et non dans le HTML initial. Les outils d'automatisation de navigateur de Python (Playwright, Selenium) exécutent JavaScript comme un vrai navigateur, vous permettant de :
- Déclencher le défilement infini
- Cliquez sur les boutons "Afficher plus"
- Attendre que le contenu apparaisse
- Interagir avec les éléments de la page
3. Fonctionnalités Anti-Détection Intégrées
Les bibliothèques Python modernes sont livrées avec des capacités de furtivité prêtes à l'emploi :
# Masquer les indicateurs d'automatisation
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
Ces indicateurs empêchent Google de détecter votre script comme un bot.
4. Pipeline de Traitement de Données Transparent
Avec Python, vous scrapez → nettoyez → analysez → exportez le tout dans un seul script. Aucun changement d'outil requis.
Le Défi : Pourquoi Google Rend le Scraping Difficile
Google emploie plusieurs couches anti-scraping. Comprendre cela vous aide à construire des scrapers résilients.
1. Chargement de Contenu Dynamique
Les avis Google ne se chargent pas tous en même temps. Au lieu de cela :
- Le chargement initial de la page montre 10 à 20 avis
- Des avis supplémentaires se chargent via AJAX au fur et à mesure que vous faites défiler
- Chaque lot nécessite des requêtes réseau séparées
- Le mécanisme change fréquemment
Solution : Utilisez l'automatisation de navigateur (Playwright/Selenium) qui exécute JavaScript et simule le défilement.
2. Détection de Bots Sophistiquée
Google analyse :
- Empreinte du navigateur — Résolution d'écran, polices installées, fuseau horaire
- Modèles comportementaux — Mouvements de la souris, vitesse de défilement, timing des clics
- Fréquence des requêtes — Détection des modèles de requêtes non humains
- Réputation IP — Signalement des adresses suspectes
Solution : Faites tourner des proxies, ajoutez des délais aléatoires, utilisez des agents utilisateurs réalistes.
3. Limitation de Taux et CAPTCHA
Frappez Google trop fort, et vous ferez face à :
- Blocages IP temporaires (24 à 48 heures)
- Défis CAPTCHA
- Refus d'accès complet
- Throttling progressif
Solution : Mettez en œuvre un throttling des requêtes (délais de 1 à 3 secondes entre les actions).
4. Structure HTML en Évolution Constante
Google met régulièrement à jour la structure de sa page, cassant les sélecteurs CSS du jour au lendemain.
Solution : Utilisez plusieurs sélecteurs de secours et des requêtes basées sur les attributs au lieu de noms de classe fragiles.
Méthode 1 : Playwright — L'Approche Moderne
Playwright est le choix recommandé pour 2025. Il est plus rapide que Selenium, possède de meilleures fonctionnalités anti-detection et gère sans effort les sites modernes riches en JavaScript.
Configuration de Playwright
Tout d'abord, créez un environnement virtuel et installez les dépendances :
# Créer un environnement virtuel
python -m venv google_scraper
source google_scraper/bin/activate # Sur Windows : google_scraper\Scripts\activate
# Installer les paquets requis
pip install playwright pandas beautifulsoup4 lxml emoji
# Installer le navigateur
playwright install chromium
Code Complet du Scraper Playwright
Voici un scraper prêt pour la production qui gère les complexités des avis Google :
from playwright.sync_api import sync_playwright
import pandas as pd
import re
import emoji
import logging
import time
import random
from datetime import datetime
# Configurer la journalisation
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class GoogleReviewsScraper:
def __init__(self, headless=True):
self.headless = headless
self.reviews_data = []
def clean_text(self, text):
"""Supprimer les emojis et normaliser le texte"""
if not text:
return ""
text = emoji.replace_emoji(text, replace='')
text = re.sub(r'\s+', ' ', text).strip()
return text
def random_delay(self, min_delay=1, max_delay=3):
"""Ajouter des délais aléatoires pour imiter le comportement humain"""
delay = random.uniform(min_delay, max_delay)
time.sleep(delay)
def initialize_browser(self):
"""Initialiser Playwright avec des paramètres furtifs"""
playwright = sync_playwright().start()
browser = playwright.chromium.launch(
headless=self.headless,
args=[
'--disable-blink-features=AutomationControlled',
'--disable-extensions',
'--no-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu'
]
)
context = browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
viewport={'width': 1366, 'height': 768}
)
page = context.new_page()
# Masquer la propriété webdriver
page.add_init_script("""
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined,
});
""")
return playwright, browser, page
def search_business(self, page, business_name):
"""Rechercher une entreprise sur Google Maps"""
try:
page.goto("https://www.google.com/maps", wait_until="networkidle")
self.random_delay(2, 4)
# Trouver la boîte de recherche et entrer le nom de l'entreprise
search_box = page.locator("input[id='searchboxinput']")
search_box.fill(business_name)
search_box.press("Enter")
# Attendre que les résultats se chargent
page.wait_for_timeout(5000)
logger.info(f"Recherche de : {business_name}")
return True
except Exception as e:
logger.error(f"Erreur lors de la recherche de l'entreprise : {e}")
return False
def navigate_to_reviews(self, page):
"""Naviguer vers la section des avis"""
try:
# Chercher l'onglet des avis
reviews_tab = page.get_by_role("tab", name=re.compile("Avis|avis", re.IGNORECASE))
if reviews_tab.is_visible():
reviews_tab.click()
page.wait_for_timeout(3000)
logger.info("Navigué vers la section des avis")
return True
else:
logger.warning("Onglet des avis non trouvé")
return False
except Exception as e:
logger.error(f"Erreur lors de la navigation vers les avis : {e}")
return False
def scroll_and_load_reviews(self, page, max_reviews=100):
"""Faire défiler pour charger plus d'avis dynamiquement"""
loaded_reviews = 0
scroll_attempts = 0
max_scroll_attempts = 20
while loaded_reviews < max_reviews and scroll_attempts < max_scroll_attempts:
try:
# Faire défiler vers le bas
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
self.random_delay(2, 4)
# Compter les avis actuels
current_reviews = page.locator('[data-review-id]').count()
if current_reviews > loaded_reviews:
loaded_reviews = current_reviews
logger.info(f"Chargé {loaded_reviews} avis...")
scroll_attempts = 0 # Réinitialiser le compteur
else:
scroll_attempts += 1
# Essayer de cliquer sur le bouton "Plus d'avis" si disponible
try:
more_button = page.locator("button:has-text('Plus'), button:has-text('plus')")
if more_button.is_visible():
more_button.click()
self.random_delay(2, 3)
except:
pass
except Exception as e:
logger.error(f"Erreur lors du défilement : {e}")
break
logger.info(f"Chargement terminé. Total des avis : {loaded_reviews}")
return loaded_reviews
def extract_review_data(self, page):
"""Extraire les données d'avis individuelles de la page chargée"""
reviews = []
try:
review_elements = page.locator('[data-review-id]').all()
for element in review_elements:
try:
review_data = {}
# Extraire le nom de l'évaluateur
try:
name_element = element.locator('div[class*="name"] span').first
review_data['reviewer_name'] = name_element.inner_text() if name_element.is_visible() else "Anonyme"
except:
review_data['reviewer_name'] = "Anonyme"
# Extraire l'évaluation
try:
rating_element = element.locator('[role="img"][aria-label*="star"]').first
if rating_element.is_visible():
rating_text = rating_element.get_attribute('aria-label')
rating_match = re.search(r'(\d+)', rating_text)
review_data['rating'] = int(rating_match.group(1)) if rating_match else None
else:
review_data['rating'] = None
except:
review_data['rating'] = None
# Extraire le texte de l'avis
try:
text_elements = element.locator('span[class*="review-text"], div[class*="review-text"]').all()
review_text = ""
for text_elem in text_elements:
if text_elem.is_visible():
review_text += text_elem.inner_text() + " "
review_data['review_text'] = self.clean_text(review_text.strip())
except:
review_data['review_text'] = ""
# Extraire la date
try:
date_element = element.locator('span[class*="date"], div[class*="date"]').first
review_data['review_date'] = date_element.inner_text() if date_element.is_visible() else "Inconnu"
except:
review_data['review_date'] = "Inconnu"
# Extraire le nombre d'aides
try:
helpful_element = element.locator('[aria-label*="helpful"], [aria-label*="Helpful"]').first
if helpful_element.is_visible():
helpful_text = helpful_element.get_attribute('aria-label')
helpful_match = re.search(r'(\d+)', helpful_text)
review_data['helpful_count'] = int(helpful_match.group(1)) if helpful_match else 0
else:
review_data['helpful_count'] = 0
except:
review_data['helpful_count'] = 0
# Ajouter uniquement les avis avec un contenu textuel réel
if review_data['review_text']:
reviews.append(review_data)
except Exception as e:
logger.warning(f"Erreur lors de l'extraction d'un avis individuel : {e}")
continue
logger.info(f"Extraction réussie de {len(reviews)} avis")
return reviews
except Exception as e:
logger.error(f"Erreur lors de l'extraction des avis : {e}")
return []
def scrape_reviews(self, business_name, max_reviews=100):
"""Méthode principale de scraping"""
playwright, browser, page = self.initialize_browser()
try:
# Rechercher l'entreprise
if not self.search_business(page, business_name):
return []
# Naviguer vers l'onglet des avis
if not self.navigate_to_reviews(page):
return []
# Charger les avis en faisant défiler
self.scroll_and_load_reviews(page, max_reviews)
# Extraire les données des avis
reviews = self.extract_review_data(page)
self.reviews_data = reviews
return reviews
except Exception as e:
logger.error(f"Le scraping a échoué : {e}")
return []
finally:
browser.close()
playwright.stop()
def save_to_csv(self, filename="google_reviews.csv"):
"""Enregistrer les avis dans un fichier CSV"""
if self.reviews_data:
df = pd.DataFrame(self.reviews_data)
df['extraction_date'] = datetime.now().isoformat()
df.to_csv(filename, index=False, encoding='utf-8')
logger.info(f"Avis enregistrés dans {filename}")
print(f"✅ Exporté {len(self.reviews_data)} avis dans {filename}")
else:
logger.warning("Aucun avis à enregistrer")
# Exemple d'utilisation
if __name__ == "__main__":
scraper = GoogleReviewsScraper(headless=False) # Mettre à True pour la production
business_name = "Starbucks Times Square New York"
reviews = scraper.scrape_reviews(business_name, max_reviews=50)
if reviews:
scraper.save_to_csv(f"avis_{business_name.replace(' ', '_')}.csv")
print(f"✅ Scraping réussi de {len(reviews)} avis !")
else:
print("❌ Aucun avis n'a été scrapé.")
Comment Ce Scraper Fonctionne
1. Configuration Furtive
Le scraper cache les indicateurs d'automatisation que Google utilise pour détecter les bots :
options.add_argument("--disable-blink-features=AutomationControlled")
page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
2. Délais Aléatoires
Au lieu de lancer des requêtes instantanément, le scraper attend 1 à 3 secondes entre les actions pour imiter la navigation humaine.
3. Défilement Dynamique
Il fait défiler jusqu'en bas de la section des avis à plusieurs reprises, déclenchant le mécanisme de défilement infini de Google pour charger plus d'avis.
4. Gestion des Erreurs Robuste
Si un sélecteur échoue (parce que Google a changé le HTML), le scraper essaie des sélecteurs de secours au lieu de planter.
5. Nettoyage des Données
Les avis sont nettoyés pour supprimer les emojis, normaliser les espaces et garantir des données de qualité.
Méthode 2 : Selenium — L'Alternative Éprouvée
Bien que Playwright soit plus rapide, Selenium reste la référence en matière de compatibilité et dispose d'une communauté massive. Utilisez Selenium si vous avez besoin d'un support maximal pour les navigateurs ou si vous avez une infrastructure Selenium existante.
Installation de Selenium
pip install selenium webdriver-manager pandas beautifulsoup4
# Télécharger ChromeDriver (géré automatiquement par webdriver-manager)
Implémentation Complète de Selenium
```python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.action_chains import ActionChains from selenium.common.exceptions import TimeoutException, NoSuchElementException import pandas as pd import time import random import re import logging from datetime import datetime
logging.basicConfig(level=logging.INFO) logger = logging.getLogger(name)
class SeleniumGoogleReviewsScraper: def init(self, headless=True): self.headless = headless self.driver = None self.wait = None self.reviews_data = []
def setup_driver(self):
"""Configurer et initialiser le driver Chrome"""
options = Options()
if self.headless:
options.add_argument("--headless")
# Mesures anti-détection
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
options.add_argument("--disable-extensions")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1366,768")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
self.driver = webdriver.Chrome(options=options)
# Masquer la propriété webdriver
self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined,});")
self.wait = WebDriverWait(self.driver, 20)
logger.info("Driver Chrome initialisé")
def random_delay(self, min_seconds=1, max_seconds=3):
"""Ajouter des délais aléatoires entre les actions"""
delay = random.uniform(min_seconds, max_seconds)
time.sleep(delay)
def search_google_maps(self, business_name):
"""Rechercher une entreprise sur Google Maps"""
try:
self.
Prêt à commencer ?
Accédez à toutes les entreprises Google Maps, enrichies avec emails et données légales.
Essayer IBLead gratuitementArticles similaires
10 conseils éprouvés pour inciter les clients à laisser plus d'avis sur Google Maps
Découvrez 10 stratégies pratiques pour augmenter les avis sur Google Maps. Timing, incitations, QR codes et tactiques de réponse efficaces.
7 erreurs de cold email à éviter : exemples et modèles
Évitez ces 7 erreurs de cold email pour améliorer vos taux de réponse. Exemples réels, modèles AIDA et solutions éprouvées.
ABM Données Google Maps : Le Guide Stratégique Complet
Découvrez comment les données Google Maps pour le marketing basé sur les comptes génèrent 208 % de revenus supplémentaires.