Aviso legal: Este artículo se centra exclusivamente en el acceso a datos públicos que no requieren inicio de sesión. Debes respetar los Términos de Servicio de Yelp, la Computer Fraud and Abuse Act (CFAA) en EE. UU. y el GDPR en la UE respecto al tratamiento de datos personales. No fomentamos el scraping de contenido protegido por inicio de sesión ni el uso de datos de reseñadores con fines no legítimos.
Si estás construyendo un dataset de negocios locales o analizando reputación online, probablemente te has preguntado cómo scrapear Yelp de forma fiable en 2026. Yelp es una de las fuentes más ricas de datos de negocios locales —perfiles, categorías, horarios, valoraciones y texto de reseñas— pero su infraestructura anti-bot, basada en PerimeterX (ahora HUMAN), bloquea la mayoría de intentos desde IPs de datacenter en cuestión de minutos. En esta guía verás qué datos son accesibles públicamente, cómo Yelp defiende su perímetro, y cómo usar proxies residenciales rotativos con geo-segmentación para mantener un flujo de datos estable y respetuoso con la ley.
Qué datos de Yelp son accesibles públicamente sin inicio de sesión
Yelp expone una cantidad considerable de información sin requerir autenticación. Los perfiles de negocio en la ruta /biz/<slug> incluyen nombre, dirección, teléfono, categorías, horarios de apertura, atributos (parking, wifi, etc.), valoración promedio (1–5 estrellas), número total de reseñas y un extracto de las tres reseñas más destacadas. Esta información es visible en el HTML renderizado y también embebida en un blob JSON dentro de una etiqueta <script> con el identificador __INITIAL_STATE__, que el frontend de React utiliza para hidratar la página.
Las reseñas, por el contrario, se cargan parcialmente en la página inicial y el resto se obtiene vía una petición AJAX a un endpoint interno (a menudo referenciado como review_feed o similar) que devuelve JSON con lotes de reseñas paginadas. Cada reseña incluye el texto completo, la valoración del usuario, la fecha y un identificador del autor. Importante: aunque los nombres de usuario y avatares son públicos, bajo el GDPR de la UE estos datos se consideran datos personales; debes minimizar su retención y anonimizar cuando sea posible.
La Fusion API oficial de Yelp ofrece acceso estructurado a datos de negocios, pero impone un límite duro: solo devuelve 3 reseñas por negocio en su endpoint /reviews, y un máximo de 50 resultados por búsqueda con un límite de 5,000 llamadas diarias en el plan gratuito. Para casos de uso que requieren el corpus completo de reseñas de un negocio (análisis de sentimiento, detección de tendencias, entrenamiento de modelos), el scraping de la página pública sigue siendo la única vía práctica.
Comparación: Scraping web vs Fusion API
| Aspecto | Scraping web (página pública) | Fusion API oficial |
|---|---|---|
| Reseñas por negocio | Todas las visibles (cientos) | Máximo 3 |
| Resultados de búsqueda | Sin límite duro (con paginación) | 50 por petición, 5,000/día |
| Autenticación | No requerida | API key requerida |
| Riesgo de bloqueo | Alto (PerimeterX) | Bajo (rate limiting) |
| Coste de infraestructura | Proxies residenciales + compute | Gratuito hasta 5,000 calls/día |
Defensas anti-bot de Yelp: PerimeterX/HUMAN, TLS fingerprinting y CAPTCHAs
Yelp utiliza HUMAN Security (anteriormente PerimeterX) como su principal capa de defensa contra bots automatizados. El sistema funciona en varias capas:
- Cookie _px3 y sensor challenge: Cuando un navegador carga la página, PerimeterX ejecuta un script JavaScript que genera un token de sensor criptográfico. Este token se envía como cookie
_px3en cada petición subsiguiente. Sin un token válido, las peticiones desde IPs sospechosas reciben un HTTP 403 o son redirigidas a una página de CAPTCHA. - IP reputation scoring: PerimeterX mantiene una base de datos de reputación de IPs. Las IPs de datacenter conocidas (AWS, DigitalOcean, OVH) reciben una puntuación de riesgo alta. Tras 3–5 peticiones desde una IP de datacenter, el sistema puede activar un bloqueo temporal de 5–15 minutos o un CAPTCHA interactiva.
- TLS fingerprinting (JA3/JA4): El servidor inspecciona el handshake TLS del cliente. Bibliotecas como
requestsde Python onode-fetchproducen huellas TLS distintas a las de Chrome o Firefox reales, lo que permite a PerimeterX identificar clientes no-browser incluso con un User-Agent válido. - Behavioral analysis: Patrones de navegación demasiado rápidos o secuenciales (visitar 50 perfiles en 30 segundos sin interacción) disparan alertas adicionales.
Esto significa que un Yelp review scraper ingenuo que use requests con una IP de datacenter será bloqueado en menos de 10 peticiones en la mayoría de los casos. La solución requiere dos componentes: una red de IPs residenciales de alta reputación y un cliente HTTP que minimice las diferencias de fingerprint respecto a un navegador real.
Por qué necesitas proxies residenciales rotativos con geo-segmentación US
Los proxies residenciales asignan IPs asignadas por ISP a hogares reales, lo que les da una puntuación de reputación baja (poco sospechosa) en los sistemas de HUMAN/PerimeterX. Sin embargo, no todas las IPs residenciales son iguales: Yelp sirve resultados de búsqueda localizados según la geolocalización de la IP de origen. Si tu IP residencial está en Frankfurt, una búsqueda de "restaurantes en Austin, TX" puede devolver resultados sesgados o incompletos.
Para obtener Yelp business data precisa y consistente, necesitas proxies residenciales rotativos con geo-segmentación a nivel de ciudad en EE. UU. Esto te permite:
- Solicitar resultados de negocios como si estuvieras físicamente en esa ciudad, obteniendo el mismo conjunto de resultados que vería un usuario local.
- Distribuir tus peticiones entre múltiples IPs residenciales US, evitando que una sola IP acumule suficiente tráfico para disparar el bloqueo de PerimeterX.
- Rotar IPs por petición (sin sesión sticky) para maximizar el anonimato, o mantener sesiones sticky de 10–30 minutos cuando necesites continuidad (por ejemplo, para paginar reseñas de un mismo negocio sin que el token de sensor caduque).
ProxyHat ofrece geo-segmentación a nivel de país y ciudad mediante flags en el nombre de usuario. Por ejemplo, user-country-US-city-austin te asigna una IP residencial en Austin, Texas, ideal para scrapear negocios locales de esa zona.
Implementación práctica: Python con requests y ProxyHat
A continuación se muestra un ejemplo funcional en Python que extrae reseñas de un negocio de Yelp usando el proxy HTTP de ProxyHat con geo-segmentación US. El script obtiene la página del negocio, extrae el blob __INITIAL_STATE__ embebido, y parsea una reseña truncada.
import requests
import re
import json
# ProxyHat HTTP proxy con geo-segmentación US, ciudad Austin
proxy_url = "http://user-country-US-city-austin:PASSWORD@gate.proxyhat.com:8080"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/131.0.0.0 Safari/537.36"
),
"Accept-Language": "en-US,en;q=0.9",
"Accept": (
"text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8"
),
}
business_slug = "torchys-tacos-austin"
url = f"https://www.yelp.com/biz/{business_slug}"
resp = requests.get(url, proxies=proxies, headers=headers, timeout=30)
if resp.status_code != 200:
print(f"Error {resp.status_code} — posible bloqueo de PerimeterX")
exit(1)
# Extraer el blob __INITIAL_STATE__ del HTML
match = re.search(
r'"INITIAL_STATE__":\s*({.*?})\s*,\s*"',
resp.text,
re.DOTALL
)
if not match:
# Alternativa: buscar el script tag que contiene el JSON
match = re.search(
r'window\["__INITIAL_STATE__"\]\s*=\s*({.*?});',
resp.text,
re.DOTALL
)
if match:
state = json.loads(match.group(1))
# Navegar la estructura para encontrar reseñas
# La ruta exacta puede variar; aquí un ejemplo simplificado
biz_data = state.get("bizDetailsPageState", {})
reviews = biz_data.get("reviews", [])
if reviews:
review = reviews[0]
print(f"Autor: {review.get('author', {}).get('name', 'N/A')}")
print(f"Rating: {review.get('rating', 'N/A')}")
text = review.get('comment', {}).get('text', '')
print(f"Reseña (truncada): {text[:200]}...")
else:
print("No se encontraron reseñas en INITIAL_STATE")
else:
print("No se encontró __INITIAL_STATE__ en el HTML")
Este ejemplo usa el gateway HTTP de ProxyHat en el puerto 8080. La flag -country-US-city-austin asegura que la IP de salida sea residencial y esté geolocalizada en Austin, lo que produce resultados de búsqueda consistentes con un usuario local y reduce la probabilidad de que PerimeterX asocie la IP con tráfico automatizado.
Rotación de IP por petición
Para distribuir el tráfico entre múltiples IPs, puedes omitir el flag de sesión (cada petición obtiene una IP nueva) o generar identificadores de sesión únicos:
import uuid
def get_proxy_with_session(city="austin"):
session_id = uuid.uuid4().hex[:12]
user = f"user-country-US-city-{city}-session-{session_id}"
return f"http://{user}:PASSWORD@gate.proxyhat.com:8080"
# Cada llamada usa una IP distinta
for slug in ["torchys-tacos-austin", "franklin-bbq-austin", "uce-austin"]:
proxy = get_proxy_with_session()
proxies = {"http": proxy, "https": proxy}
resp = requests.get(
f"https://www.yelp.com/biz/{slug}",
proxies=proxies,
headers=headers,
timeout=30,
)
print(f"{slug}: HTTP {resp.status_code}, longitud {len(resp.text)}")
Implementación en Node.js con SOCKS5 (puerto 1080)
Para casos donde necesitas el protocolo SOCKS5 —por ejemplo, para usarlo con bibliotecas que no soportan proxies HTTP de forma nativa o para evitar inspección intermedia— ProxyHat expone el puerto 1080:
const { SocksProxyAgent } = require('socks-proxy-agent');
const fetch = require('node-fetch');
const proxyUser = 'user-country-US-city-austin-session-node01';
const proxyPass = 'PASSWORD';
const proxyUrl = `socks5://${proxyUser}:${proxyPass}@gate.proxyhat.com:1080`;
const agent = new SocksProxyAgent(proxyUrl);
const headers = {
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ' +
'AppleWebKit/537.36 (KHTML, like Gecko) ' +
'Chrome/131.0.0.0 Safari/537.36',
'Accept-Language': 'en-US,en;q=0.9',
};
async function scrapeYelpBiz(slug) {
const url = `https://www.yelp.com/biz/${slug}`;
const resp = await fetch(url, { agent, headers, timeout: 30000 });
if (!resp.ok) {
console.error(`HTTP ${resp.status} para ${slug}`);
return null;
}
const html = await resp.text();
// Buscar __INITIAL_STATE__
const match = html.match(/"INITIAL_STATE__":\s*({.*?})\s*,\s*"/s);
if (!match) {
console.error('No se encontró INITIAL_STATE');
return null;
}
const state = JSON.parse(match[1]);
const reviews =
state?.bizDetailsPageState?.reviews ?? [];
if (reviews.length > 0) {
const r = reviews[0];
console.log({
author: r?.author?.name ?? 'N/A',
rating: r?.rating ?? 'N/A',
text: (r?.comment?.text ?? '').slice(0, 200),
});
}
return state;
}
scrapeYelpBiz('torchys-tacos-austin').catch(console.error);
Paginación, rate-limit pacing y sesiones sticky
El scraping de reseñas completas de un negocio con cientos de reseñas requiere paginación. Yelp carga las primeras reseñas en el HTML inicial y las subsequentes vía llamadas AJAX. Cada "página" de reseñas suele contener 10–20 reseñas. Para paginar sin perder continuidad de sesión, usa el flag -session- de ProxyHat para mantener la misma IP durante toda la secuencia de paginación de un negocio.
Estrategia de pacing recomendada
- Delay entre peticiones: 2–5 segundos con jitter aleatorio (no uses intervalos fijos, son detectables).
- Concurrencia: Máximo 5–10 peticiones simultáneas desde IPs distintas; nunca múltiples peticiones desde la misma IP en paralelo.
- Sesión sticky por negocio: Usa
-session-biz-{slug}para mantener la misma IP mientras paginas un negocio. Cambia de sesión al pasar al siguiente negocio. - Rotación de User-Agent: Mantén un pool de 8–12 User-Agents de Chrome y Firefox recientes y rota por petición. Nunca uses User-Agents obsoletos o inconsistentes (por ejemplo, Chrome en Windows NT 6.1).
- Límite diario: Establece un techo de 3,000–5,000 peticiones por día por conjunto de IPs para evitar patrones detectables.
Rotación de User-Agents en Python
import random
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 14.5; rv:133.0) Gecko/20100101 Firefox/133.0",
]
def get_random_ua():
return random.choice(USER_AGENTS)
import time
def scrape_with_pacing(slug, session_id):
proxy = f"http://user-country-US-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}
headers = {
"User-Agent": get_random_ua(),
"Accept-Language": "en-US,en;q=0.9",
}
resp = requests.get(f"https://www.yelp.com/biz/{slug}", proxies=proxies, headers=headers, timeout=30)
# Jitter aleatorio: 2–5 segundos
time.sleep(random.uniform(2, 5))
return resp
Configuración de ProxyHat y enlaces internos
ProxyHat está diseñado para casos de uso de scraping a escala. La configuración de geo-segmentación y rotación se controla enteramente desde el nombre de usuario, sin necesidad de una API adicional. Aquí tienes los recursos relevantes:
- Consulta las documentación oficial de ProxyHat para detalles sobre parámetros avanzados de sesión y rotación.
- Revisa los planes y precios de ProxyHat para estimar costes según tu volumen de peticiones.
- Explora el caso de uso de web scraping con proxies residenciales para más patrones de implementación.
- Si también necesitas tracking de SERPs, ProxyHat soporta geo-segmentación para Google y otros motores de búsqueda.
- Consulta la lista de ubicaciones disponibles para verificar cobertura por ciudad.
Errores comunes y casos límite
1. No manejar el challenge de PerimeterX
Si recibes un HTTP 403 o una página con _px en el cuerpo, PerimeterX ha detectado tu cliente. Soluciones: cambia de IP (rota la sesión), añade un delay más largo, o considera usar un navegador headless como Playwright con un plugin anti-detección para generar el token _px3 de forma legítima.
2. Estructura de __INITIAL_STATE__ cambiante
Yelp actualiza su frontend con frecuencia. La ruta JSON dentro de __INITIAL_STATE__ puede cambiar entre deploys. Construye tu parser de forma defensiva: usa jsonpath-ng o búsquedas recursivas por clave en lugar de rutas hardcodeadas.
3. Rate limiting por ciudad
Si concentras todo tu tráfico en una sola ciudad (por ejemplo, -city-austin), el pool de IPs disponibles puede agotarse. Distribuye el tráfico entre múltiples ciudades o usa -country-US sin especificar ciudad cuando la localización exacta no sea crítica.
4. Datos personales en reseñas
El texto de reseñas puede contener información personal (nombres, ubicaciones, detalles de empleados). Bajo el GDPR, debes tener una base legal para procesar estos datos y implementar medidas de minimización. Considera anonimizar nombres de usuarios y no almacenar avatares.
Scraping ético: cuándo usar la API oficial en lugar de scraping
El scraping de datos públicos es legal en muchas jurisdicciones cuando se realiza respetando los Términos de Servicio y sin causar daño a la infraestructura del sitio. Sin embargo, hay casos donde la Fusion API de Yelp es la opción correcta:
- Necesitas solo metadatos de negocios (nombre, dirección, teléfono, categorías, rating): la Fusion API los proporciona de forma estructurada y sin riesgo de bloqueo.
- Necesitas 3 o menos reseñas por negocio: el endpoint
/reviewsde la API las devuelve sin necesidad de scraping. - Tu volumen es menor a 5,000 llamadas/día: el plan gratuito de la API es suficiente y más fiable que cualquier scraper.
- Necesitas datos en tiempo casi real: la API tiene latencia menor y SLA mejor definido que el scraping web.
Por el contrario, el scraping web es necesario cuando necesitas el corpus completo de reseñas (más de 3), datos históricos, o información que la API no expone (como atributos específicos del negocio o fotos). En estos casos, sigue estas prácticas:
- Respeta el
robots.txtde Yelp y no scrapees rutas explícitamente prohibidas. - No accedas a contenido que requiera inicio de sesión. Los datos de usuarios autenticados están fuera del ámbito de esta guía.
- Implementa rate limiting conservador (máximo 1 petición cada 2–5 segundos por IP).
- No republishes reseñas completas con atribución del autor sin consentimiento; agrega valor mediante agregación, análisis o anonimización.
- Si operas bajo jurisdicción de la UE, documenta tu base legal para el tratamiento de datos personales (interés legítimo, consentimiento, etc.) y ofrece un mecanismo de exclusión.
Puntos clave (Key Takeaways)
Yelp expone datos de negocios y reseñas públicamente sin login, pero la Fusion API oficial limita las reseñas a 3 por negocio. Para datasets completos, el scraping web sigue siendo necesario, pero requiere proxies residenciales rotativos con geo-segmentación US para evadir PerimeterX/HUMAN.
- Datos públicos accesibles: perfiles de negocio, rating, categorías, horarios y reseñas visibles en
/biz/<slug>sin autenticación. - Defensa principal: PerimeterX/HUMAN con cookie
_px3, TLS fingerprinting y IP reputation scoring. IPs de datacenter se bloquean tras 3–5 peticiones. - Solución de proxy: proxies residenciales rotativos con geo-segmentación US (ej.
-country-US-city-austin) para resultados localizados y evasión de bloqueos. - Implementación: extrae
__INITIAL_STATE__del HTML para datos estructurados; usa sesiones sticky para paginación y rotación de IP por negocio. - Pacing: 2–5 segundos entre peticiones con jitter, máximo 5–10 conexiones concurrentes, rotación de User-Agents.
- Ética: respeta ToS, robots.txt y GDPR; usa la Fusion API cuando cubra tus necesidades; no accedas a contenido con login.
Preguntas frecuentes
¿Es legal scrapear Yelp?
El scraping de datos públicamente accesibles sin inicio de sesión es legal en muchas jurisdicciones, pero está sujeto a los Términos de Servicio de Yelp y a leyes como la CFAA en EE. UU. y el GDPR en la UE. Debes evitar acceder a contenido protegido por login, respetar el robots.txt, y no usar datos personales de reseñadores sin una base legal. Consulta siempre con un abogado antes de operar a escala comercial.
¿Qué tipo de proxy funciona mejor para scrapear Yelp?
Los proxies residenciales rotativos con geo-segmentación US son la mejor opción. Las IPs residenciales tienen alta reputación en los sistemas de PerimeterX/HUMAN, y la geo-segmentación por ciudad asegura que los resultados de búsqueda sean consistentes con un usuario local. Los proxies de datacenter se bloquean en 3–5 peticiones. Los proxies móviles también funcionan pero son más caros y no ofrecen ventaja adicional para Yelp.
¿Cómo evito los bloqueos de PerimeterX al scrapear Yelp?
Usa proxies residenciales rotativos, rota IPs por petición o por negocio, implementa delays de 2–5 segundos con jitter aleatorio, rota User-Agents de navegadores reales, y mantén sesiones sticky durante la paginación de un mismo negocio. Evita la concurrencia alta desde una sola IP. Si recibes HTTP 403 con _px en el cuerpo, cambia de IP inmediatamente y reduce tu frecuencia de peticiones.
¿Puedo obtener todas las reseñas de un negocio de Yelp?
Sí, mediante scraping web. La página pública de cada negocio muestra las primeras reseñas en el HTML y las carga incrementalmente vía AJAX. Cada lote contiene 10–20 reseñas. La Fusion API oficial solo devuelve 3 reseñas por negocio, por lo que para análisis de sentimiento o entrenamiento de modelos necesitas scraping. Asegúrate de paginar con sesiones sticky y respetar rate limits conservadores.
¿Qué es __INITIAL_STATE__ en Yelp?
Es un blob JSON embebido en una etiqueta <script> del HTML de Yelp que contiene los datos del negocio y las primeras reseñas en formato estructurado. El frontend de React lo usa para hidratar la página. Extraerlo es más fiable que parsear el HTML renderizado, pero la estructura interna puede cambiar entre deploys, así que construye parsers defensivos.






