Avertissement légal : Le scraping de Yelp peut violer ses Conditions d'Utilisation (ToS). Aux États-Unis, le Computer Fraud and Abuse Act (CFAA) s'applique aux accès non autorisés. Dans l'UE, le RGPD (GDPR) régit le traitement des données personnelles, y compris les avis identifiant leurs auteurs. Ce guide couvre uniquement l'accès aux données publiques visibles sans connexion. Consultez un avocat avant tout déploiement en production.
Si vous construisez des jeux de données d'entreprises locales — pour l'analyse de marché, la veille concurrentielle ou l'enrichissement de données — vous avez probablement envisagé de scraper Yelp. Yelp reste l'une des plus grandes sources d'avis de consommateurs au monde, avec plus de 250 millions d'avis cumulés selon ses communications publiques. Mais en 2026, extraire ces données à l'échelle est devenu un défi technique sérieux : PerimeterX (désormais HUMAN Security) bloque les requêtes automatisées, les empreintes TLS sont inspectées, et les datacenter IPs sont neutralisées après quelques requêtes seulement.
Ce guide explique comment scraper les fiches entreprises et avis Yelp en 2026 de manière fiable, avec des proxies résidentiels rotatifs, des exemples de code Python et Node.js, et des stratégies de pagination et de pacing. Nous couvrons uniquement les données accessibles publiquement, sans connexion.
Comment scraper les fiches entreprises et avis Yelp en 2026 : ce qui est accessible
Avant d'écrire la moindre ligne de code, il est crucial de comprendre ce qui est publiquement accessible sans login sur Yelp, et ce qui ne l'est pas.
Données visibles sans connexion
- Fiche entreprise à l'URL
/biz/<slug>: nom, adresse, téléphone, horaires, catégories, fourchette de prix, attributs (parking, wifi, etc.). - Note globale (1 à 5 étoiles) et nombre d'avis.
- Texte des avis, nom de l'auteur (pseudonyme public), date, note individuelle, photos.
- Photos uploadées par les utilisateurs et par le commerçant.
Toutes ces informations sont rendues côté serveur dans le HTML initial de la page /biz/<slug>. Yelp embarque également un objet JSON massif dans une variable JavaScript __INITIAL_STATE__ (ou similaire selon les mises à jour front-end) qui contient une grande partie de ces données sous forme structurée — un véritable trésor pour un Yelp review scraper.
L'API officielle Fusion et sa limite de 3 avis
Yelp propose une API officielle appelée Fusion. Elle permet de rechercher des entreprises par géolocalisation, catégorie ou mot-clé, et de récupérer les détails d'une fiche. Cependant, l'endpoint reviews de Fusion ne renvoie que 3 avis maximum par entreprise, triés par pertinence. Pour un projet nécessitant l'historique complet des avis, l'API est insuffisante.
| Critère | API Fusion (officielle) | Scraping web (pages publiques) |
|---|---|---|
| Avis par entreprise | 3 maximum | Tous les avis paginés visibles publiquement |
| Authentification | Clé API (gratuite, quota limité) | Aucune connexion requise |
| Fiabilité | Élevée, support officiel | Variable, soumise au blocage anti-bot |
| Données disponibles | Notes, catégories, horaires, localisation | Idem + texte complet des avis, photos, commentaires |
| Risque légal | Faible (usage conforme au ToS API) | Élevé (potentielle violation ToS, CFAA, RGPD) |
| Coût infrastructure | Gratuit sous quota, puis payant | Coût de proxies résidentiels |
Règle d'or : si l'API Fusion couvre votre besoin (recherche d'entreprises, top 3 avis), utilisez-la. Ne scrapez les pages publiques que si vous avez besoin de données que l'API ne fournit pas, et uniquement dans le respect des lois applicables.
Défenses anti-bot de Yelp : PerimeterX, TLS fingerprinting et CAPTCHAs
Yelp protège ses pages avec PerimeterX, une solution anti-bot rachetée par HUMAN Security. Comprendre son fonctionnement est indispensable pour quiconque souhaite extraire des données d'entreprises Yelp à l'échelle.
Le cookie _px3 et le sensor challenge
Lorsque vous chargez une page Yelp, le script PerimeterX s'exécute côté navigateur et génère un cookie _px3. Ce cookie encode un « payload de capteur » (sensor data) qui inclut des signaux comportementaux : mouvements de souris, frappes clavier, propriétés du navigateur, timing d'exécution JavaScript. Si ce payload est absent, invalide ou suspect, PerimeterX redirige vers une page de défi (challenge) ou affiche un CAPTCHA.
Les requêtes HTTP simples (type requests Python sans navigateur) ne génèrent pas ce cookie naturellement. Après 3 à 10 requêtes depuis une IP datacenter, PerimeterX déclenche un blocage. Le seuil exact varie, mais la réputation IP est le facteur numéro un.
Empreinte TLS (TLS fingerprinting)
PerimeterX inspecte également l'empreinte TLS (JA3/JA4) de la connexion. Les bibliothèques HTTP comme requests, urllib3 ou Go http.Client produisent des empreintes TLS distinctes de celles des navigateurs réels. Une empreinte JA3 correspondant à un client HTTP programmatique est un signal fort de bot, indépendamment du User-Agent déclaré.
Pour atténuer ce risque, certains scrapers utilisent des bibliothèques comme curl-impersonate ou tls-client qui imitent les ClientHello de Chrome ou Firefox. Cependant, ces techniques ne suffisent pas sans une rotation d'IP de qualité.
CAPTCHAs et blocages après quelques requêtes datacenter
Les IPs datacenter (OVH, AWS, DigitalOcean, etc.) ont une réputation IP très faible aux yeux de PerimeterX. En pratique, depuis une IP datacenter :
- Les 2-3 premières requêtes peuvent passer.
- La 4e ou 5e requête déclenche un défi PerimeterX (page
/px/). - Au-delà, l'IP est bloquée pendant plusieurs heures.
C'est précisément là que les proxies résidentiels rotatifs entrent en jeu.
Pourquoi les proxies résidentiels rotatifs avec géo US sont indispensables
PerimeterX classe les adresses IP selon leur réputation. Les IPs résidentielles (attribuées par des FAI comme Comcast, AT&T, Verizon) sont considérées comme légitimes car elles correspondent à de vrais utilisateurs domestiques. Les IPs datacenter, au contraire, sont systématiquement suspectées.
Rotation par requête vs sessions sticky
Deux stratégies de rotation s'offrent à vous :
- Rotation par requête : chaque requête HTTP sort depuis une IP résidentielle différente. Idéal pour répartir la charge et éviter l'accumulation de signaux suspects sur une seule IP.
- Session sticky : un identifiant de session fixe maintient la même IP pendant une fenêtre donnée (par exemple 10-30 minutes). Utile pour paginer les avis d'une même entreprise sans déclencher de défi de cohérence.
Avec ProxyHat, la rotation se contrôle via le username du proxy :
- Rotation par requête :
user-country-US:pass@gate.proxyhat.com:8080 - Session sticky :
user-country-US-session-yelp01:pass@gate.proxyhat.com:8080 - Géo-ciblage ville :
user-country-US-city-austin-session-yelp01:pass@gate.proxyhat.com:8080
Pourquoi le géo-ciblage US-city matters
Yelp personnalise les résultats de recherche et parfois le contenu des fiches selon la localisation du visiteur. Si vous scrapez depuis une IP française, Yelp peut afficher des résultats différents ou rediriger vers la version internationale. Pour obtenir des résultats cohérents avec ce qu'un utilisateur à Austin, Texas verrait, utilisez -country-US-city-austin.
Consultez la page locations ProxyHat pour vérifier la couverture géographique disponible.
Exemple Python : scraper la page /biz et extraire __INITIAL_STATE__
Voici un exemple complet en Python utilisant requests avec un proxy résidentiel ProxyHat. Le script récupère la page /biz/<slug>, extrait l'objet JSON __INITIAL_STATE__ embarqué dans le HTML, et parse un avis tronqué.
import requests
import json
import re
import time
import random
# Proxy ProxyHat : résidentiel US, rotation par session
PROXY_URL = "http://user-country-US-city-austin-session-yelp01:pass@gate.proxyhat.com:8080"
proxies = {"http": PROXY_URL, "https": PROXY_URL}
# Rotation de User-Agents réalistes
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
]
def fetch_biz_page(biz_slug: str) -> dict:
"""Récupère la page /biz et extrait __INITIAL_STATE__."""
url = f"https://www.yelp.com/biz/{biz_slug}"
headers = {
"User-Agent": random.choice(USER_AGENTS),
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.yelp.com/",
"Connection": "keep-alive",
}
resp = requests.get(url, headers=headers, proxies=proxies, timeout=30)
resp.raise_for_status()
html = resp.text
# Extraire __INITIAL_STATE__ du script embarqué
# Le pattern peut varier selon les mises à jour de Yelp
match = re.search(r'__INITIAL_STATE__\s*=\s*({.*?});', html, re.DOTALL)
if not match:
# Tentative alternative : JSON dans un tag script
match = re.search(r'"__INITIAL_STATE__":\s*({.*?})\s*[,}]', html, re.DOTALL)
if not match:
raise ValueError("__INITIAL_STATE__ introuvable dans le HTML")
raw_json = match.group(1)
# Yelp peut utiliser undefined comme valeurs JSON invalides
raw_json = raw_json.replace("undefined", "null")
state = json.loads(raw_json)
return state
def extract_reviews(state: dict, max_reviews: int = 5) -> list:
"""Extrait une liste d'avis depuis __INITIAL_STATE__."""
reviews = []
# La structure exacte dépend de la version du front-end Yelp
# Chemin typique : state['bizDetailsPage']['reviews']
biz_data = state.get("bizDetailsPage", {}).get("reviewQuery", {})
review_list = biz_data.get("reviews", [])
for r in review_list[:max_reviews]:
review = {
"author": r.get("author", {}).get("markupName", ""),
"rating": r.get("rating", None),
"date": r.get("localizedDate", ""),
"text": r.get("comment", {}).get("text", "")[:200], # tronqué
}
reviews.append(review)
return reviews
# --- Exécution ---
if __name__ == "__main__":
slug = "gary-danko-san-francisco"
try:
state = fetch_biz_page(slug)
reviews = extract_reviews(state, max_reviews=3)
for i, rev in enumerate(reviews, 1):
print(f"--- Avis {i} ---")
print(f"Auteur : {rev['author']}")
print(f"Note : {rev['rating']}/5")
print(f"Date : {rev['date']}")
print(f"Texte : {rev['text']}...")
print()
except Exception as e:
print(f"Erreur : {e}")
# Pacing : attendre 3-7 secondes entre les requêtes
time.sleep(random.uniform(3, 7))
Note : La structure exacte de __INITIAL_STATE__ change régulièrement. Le code ci-dessus est un point de départ ; inspectez le JSON renvoyé pour adapter les chemins d'accès. Ne jamais hardcoder un chemin sans l'avoir vérifié sur la page courante.
Pour des projets plus ambitieux, consultez notre guide web scraping qui couvre la gestion de pools de proxies et la reprise sur erreur.
Exemple Node.js : scraping via SOCKS5 (port 1080)
Voici un exemple Node.js utilisant le proxy SOCKS5 de ProxyHat sur le port 1080. SOCKS5 est utile quand vous avez besoin d'un tunnel TCP de bas niveau, par exemple avec certaines bibliothèques de scraping headless.
const { SocksProxyAgent } = require('socks-proxy-agent');
const fetch = require('node-fetch');
// Proxy SOCKS5 ProxyHat : résidentiel US, session sticky
const PROXY_SOCKS5 = 'socks5://user-country-US-city-austin-session-yelp02:pass@gate.proxyhat.com:1080';
const agent = new SocksProxyAgent(PROXY_SOCKS5);
const USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
];
async function fetchYelpBiz(bizSlug) {
const url = `https://www.yelp.com/biz/${bizSlug}`;
const headers = {
'User-Agent': USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Referer': 'https://www.yelp.com/',
};
const resp = await fetch(url, { agent, headers, timeout: 30000 });
if (!resp.ok) {
throw new Error(`HTTP ${resp.status} — possible blocage PerimeterX`);
}
const html = await resp.text();
// Extraire __INITIAL_STATE__
const match = html.match(/__INITIAL_STATE__\s*=\s*({.*?});/s);
if (!match) {
throw new Error('__INITIAL_STATE__ introuvable');
}
let rawJson = match[1].replace(/undefined/g, 'null');
const state = JSON.parse(rawJson);
// Extraire le premier avis (tronqué)
const reviews = state?.bizDetailsPage?.reviewQuery?.reviews || [];
if (reviews.length > 0) {
const r = reviews[0];
console.log({
author: r?.author?.markupName || '',
rating: r?.rating || null,
date: r?.localizedDate || '',
text: (r?.comment?.text || '').slice(0, 200),
});
}
return state;
}
// Exécution avec pacing
(async () => {
try {
await fetchYelpBiz('gary-danko-san-francisco');
// Attendre 4 secondes avant la prochaine requête
await new Promise(r => setTimeout(r, 4000));
} catch (err) {
console.error('Erreur:', err.message);
}
})();
Pagination, rate-limit pacing et stratégies de session
Pagination des avis
Yelp pagine les avis avec un paramètre start (offset) et count sur l'endpoint /biz/<slug> ou via l'API interne review_feed. Chaque page contient généralement 10 avis. Pour scraper tous les avis d'une entreprise avec 500 avis, vous devez paginer environ 50 fois.
# Pagination des avis avec pacing
import time, random
def scrape_all_reviews(biz_slug, max_pages=50):
all_reviews = []
for page in range(max_pages):
start = page * 10
# Utiliser une session sticky pour la cohérence de pagination
proxy = f"http://user-country-US-city-austin-session-{biz_slug[:8]}:pass@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}
url = f"https://www.yelp.com/biz/{biz_slug}?start={start}"
# ... fetch + parse ...
# Pacing : 3-8 secondes entre chaque page
time.sleep(random.uniform(3, 8))
# Changer de session tous les 10 pages pour renouveler l'IP
if page > 0 and page % 10 == 0:
# La rotation de session se fait en changeant l'ID de session
pass
return all_reviews
Rate-limit pacing
Le pacing est le facteur le plus sous-estimé du scraping Yelp. PerimeterX ne détecte pas seulement les IPs et les empreintes — il détecte aussi les patterns de trafic. Un scraper qui envoie 50 requêtes en 10 secondes depuis la même IP est immédiatement flagué, même avec un proxy résidentiel.
Recommandations de pacing :
- 3 à 8 secondes entre les requêtes sur la même session IP.
- Maximum 100 requêtes par session IP avant rotation.
- Jitter aléatoire : ne pas utiliser un intervalle fixe. Un intervalle constant est un signal bot.
- Concurrency limitée : 5 à 10 sessions parallèles maximum, pas plus.
Sessions sticky pour la continuité
Quand vous paginez les avis d'une même entreprise, il est préférable de maintenir la même IP pendant toute la durée de la pagination. Si vous changez d'IP à chaque page, PerimeterX peut détecter une incohérence (un utilisateur normal ne change pas d'IP toutes les 5 secondes). Utilisez un identifiant de session stable comme -session-yelp-garydanko.
Rotation de User-Agents
Le User-Agent est le signal le plus facile à falsifier, mais aussi le plus facile à détecter si mal fait. Règles :
- Utilisez des User-Agents récents et réalistes (Chrome 120+, Firefox 120+, Safari 17+).
- Assurez la cohérence : si votre User-Agent déclare Chrome sur Windows, vos headers
Accept,Accept-Languageetsec-ch-uadoivent être cohérents. - Ne changez pas de User-Agent à chaque requête sur la même session IP — un utilisateur normal garde le même navigateur.
- Changez de User-Agent uniquement quand vous changez de session proxy.
Erreurs courantes et edge cases
1. Ignorer le statut HTTP 429 et les redirects PerimeterX
Quand PerimeterX bloque une requête, il peut renvoyer un HTTP 403, un HTTP 429, ou rediriger vers /px/ avec un HTTP 200 (page de défi). Votre scraper doit détecter ces trois cas :
if resp.status_code == 403:
# Blocage PerimeterX — changer d'IP immédiatement
rotate_session()
elif resp.status_code == 429:
# Rate limit — backoff exponentiel
time.sleep(60)
elif '/px/' in resp.url:
# Défi PerimeterX — l'IP est compromise
rotate_session()
2. Scraper des données login-walled
Certaines données Yelp ne sont visibles qu'après connexion : avis « filtrés » (not recommended), messages privés, listes personnelles. Ne scrapez jamais ces données. L'accès à du contenu derrière un login sans autorisation explicite est une violation du CFAA aux États-Unis et potentiellement du RGPD en Europe.
3. Négliger les données personnelles (RGPD)
Les avis Yelp contiennent des données personnelles : pseudonymes, photos de profil, localisation approximative. Selon le RGPD, ces données sont protégées. Si vous stockez des avis dans une base de données :
- Anonymisez ou pseudonymisez les noms d'auteurs.
- Ne stockez pas de photos de profil.
- Documentez la finalité du traitement.
- Prévoyez un mécanisme de suppression sur demande.
4. Utiliser des proxies datacenter pour Yelp
C'est l'erreur la plus fréquente. Les proxies datacenter (IPs d'hébergeurs) sont bloqués par PerimeterX en moins de 10 requêtes. Seuls les proxies résidentiels offrent une réputation IP suffisante. Les proxies mobiles (4G/5G) sont encore meilleurs mais plus coûteux.
Configuration ProxyHat : checklist de production
Pour un déploiement de scraping Yelp en production avec ProxyHat, voici la configuration recommandée :
- Type de proxy : Résidentiel rotatif (réputation IP élevée).
- Géo :
-country-USavec ciblage ville si nécessaire (ex.-city-austin,-city-san-francisco). - Session : Sticky avec un ID par entreprise scrapée (ex.
-session-yelp-garydanko). - Port :
8080pour HTTP,1080pour SOCKS5. - Gateway :
gate.proxyhat.comuniquement. - Pacing : 3-8 secondes par requête, jitter aléatoire.
- Rotation : Nouvelle session tous les 50-100 requêtes.
- Concurrency : 5-10 sessions parallèles maximum.
Consultez la documentation ProxyHat pour les détails d'authentification et les paramètres avancés. Les tarifs ProxyHat incluent des plans adaptés au scraping à grande échelle.
Scraping éthique de Yelp : quand utiliser l'API officielle
Le scraping n'est pas illégal par nature, mais il existe dans une zone grise juridique. Avant de scraper Yelp, posez-vous ces questions :
- L'API Fusion couvre-t-elle mon besoin ? Si oui, utilisez-la. C'est la solution la plus sûre, la plus fiable et la plus légale.
- Ai-je besoin des avis complets ou seulement du top 3 ? Fusion renvoie 3 avis. Si 3 suffisent, ne scrapez pas.
- Les données sont-elles publiquement accessibles sans login ? Si non, n'y accédez pas. Le CFAA sanctionne l'accès non autorisé.
- Respecté-je le
robots.txtde Yelp ? Consultezhttps://www.yelp.com/robots.txtavant tout scraping. - Suis-je conforme au RGPD ? Tout traitement de données personnelles d'avis doit avoir une base légale.
Le scraping éthique signifie : accéder uniquement aux données publiques, à un rythme raisonnable, sans dégrader le service pour les autres utilisateurs, et avec une finalité claire et légitime. Si votre use case relève du suivi SERP ou de l'analyse de marché, l'API Fusion combinée à un complément de scraping sur données publiques peut être un compromis acceptable.
Points clés à retenir
- Données publiques uniquement : fiches
/biz/<slug>, notes, avis, horaires — sans connexion.- API Fusion : gratuite mais limitée à 3 avis par entreprise. Préférez-la quand elle suffit.
- PerimeterX/HUMAN : bloque les IPs datacenter après 3-10 requêtes. Le cookie
_px3et l'empreinte TLS sont inspectés.- Proxies résidentiels US : indispensables pour survivre à la réputation IP de PerimeterX. Géo-ciblage ville pour des résultats localisés.
- Pacing : 3-8 secondes par requête, jitter aléatoire, 5-10 sessions concurrentes max.
- Sessions sticky : maintenez la même IP pendant la pagination d'une entreprise.
- Éthique et légalité : respectez
robots.txt, le CFAA, le RGPD. N'accédez jamais aux données login-walled.
Le scraping de Yelp en 2026 est techniquement possible avec les bons outils — proxies résidentiels rotatifs, pacing soigné, et parsing du JSON embarqué — mais il exige une discipline de production. Si votre besoin peut être couvert par l'API Fusion, c'est toujours la meilleure option. Pour les cas où le scraping de données publiques est nécessaire, ProxyHat fournit l'infrastructure proxy adaptée. Commencez par consulter nos offres et la documentation pour configurer vos premières sessions.






