Ważne zastrzeżenie prawne: Ten artykuł dotyczy wyłącznie dostępu do publicznie dostępnych danych na Yelp — treści widocznych bez logowania. Scrapowanie może naruszać Warunki Korzystania z Usług (Terms of Service) Yelp, a w Stanach Zjednoczonych nadużycie może podlegać ustawie CFAA (Computer Fraud and Abuse Act). W Unii Europejskiej recenzje zawierające dane osobowe podlegają RODO (GDPR). Przed rozpoczęciem prac skonsultuj się z prawnikiem i rozważ użycie oficjalnego Yelp Fusion API, jeśli pokrywa Twoje potrzeby.
Jeśli budujesz zbiory danych o lokalnych firmach — do analizy rynku, monitorowania reputacji, trenowania modeli NLP czy wzbogacania katalogów — Yelp pozostaje jednym z najbogatszych źródeł publicznych informacji o małych i średnich przedsiębiorstwach w USA. W 2026 roku jednak samo pobieranie stron nie wystarczy. Yelp wdrożył wielowarstwowe mechanizmy anty-bot, od PerimeterX (obecnie HUMAN Security) po śledzenie odcisków TLS, co sprawia, że scrapowanie z adresów datacenter kończy się blokadą po zaledwie kilku żądaniach.
W tym przewodniku pokazujemy, jak scrapować dane biznesowe z Yelp w sposób skalowalny i odpowiedzialny: co jest publicznie dostępne, jak działa obrona anty-bot, dlaczego rotacyjne proxy rezydencyjne z geo-targetowaniem są niezbędne, oraz jak zaimplementować działające snippety kodu w Pythonie i Node.js z bramką ProxyHat.
Jak scrapować dane biznesowe z Yelp — co jest publicznie dostępne bez logowania
Yelp udostępnia znaczną część danych biznesowych bez wymogu logowania. Każda firma ma profil pod adresem /biz/<slug>, gdzie slug to zwykle nazwa-firma-lokalizacja, np. /biz/gary-danko-san-francisco. Bez konta możesz odczytać:
- Nazwę firmy, kategorie, adres, telefon, stronę WWW — podstawowe dane NAP (Name, Address, Phone).
- Ocenę ogólną (1–5 gwiazdek) oraz liczbę recenzji.
- Godziny otwarcia — w formacie tekstowym i strukturalnym (często w osadzonym JSON).
- Teksty recenzji — Yelp pokazuje recenzje na stronie biznesu bez logowania, choć najnowsze mogą być ograniczone.
- Zdjęcia — miniaturki i pełne obrazy przypisane do firmy.
Co nie jest publicznie dostępne bez logowania:
- Pełna historia recenzji konkretnego użytkownika (wymaga profilu).
- Filtrowane/usunięte recenzje (Yelp ukrywa część recenzji jako „not recommended”).
- Dane analityczne właściciela firmy (dostępne tylko przez Yelp for Business).
- Prywatne wiadomości DM między użytkownikami a firmą.
Oficjalne Fusion API vs. scrapowanie
Yelp oferuje Fusion API z kluczem API. To czyste, legalne rozwiązanie — ale ma istotne ograniczenia. Endpoint GET /v3/businesses/{id} zwraca podstawowe informacje o firmie i maksymalnie 3 recenzje. Limit ten jest twardy i nie podlega negocjacji. Jeśli potrzebujesz setek lub tysięcy recenzji dla danej firmy, Fusion API nie wystarczy — i właśnie wtedy programiści sięgają po scrapowanie.
| Cecha | Fusion API | Scrapowanie stron |
|---|---|---|
| Liczba recenzji na firmę | Max 3 | Wszystkie publiczne (setki) |
| Klucz API / autoryzacja | Wymagany (API key) | Nie wymagany (publiczne strony) |
| Rate limit | ~5000 żądań/dzień (zależne od planu) | Ograniczony anty-bot, nie dokumentowany |
| Dane godzinowe | Tak (strukturalne) | Tak (w __INITIAL_STATE__) |
| Ryzyko prawne | Niskie (oficjalne ToS) | Wyższe (należy sprawdzić ToS Yelp) |
| Koszt infrastruktury | Brak (poza ew. planem API) | Proxy + serwery |
Techniczne tło: dlaczego scrapowanie Yelp jest trudne w 2026
Yelp stosuje co najmniej trzy warstwy obrony przed automatycznym pobieraniem danych. Zrozumienie każdej z nich jest kluczowe, zanim napiszesz choćby linię kodu.
1. PerimeterX / HUMAN Security
PerimeterX (obecnie część HUMAN Security) to system bot-management osadzony po stronie serwera. Działa poprzez:
- Ciasteczko
_px3— token sesyjny ustawiany przez JavaScript po rozwiązaniu wyzwania „sensor”. Brak tego ciasteczka lub jego nieprawidłowa wartość powoduje blokadę HTTP 403 lub przekierowanie do strony CAPTCHA. - Wyzwanie sensor — skrypt JS zbiera dane o przeglądarce (canvas fingerprint, WebGL, czasy zdarzeń, rozdzielczość) i wysyła je do PerimeterX. Jeśli sygnatura wygląda botowo, żądanie jest odrzucane.
- Scoring reputacji IP — adresy z zakresów datacenter (AWS, GCP, DigitalOcean) dostają niski wynik reputacji i są blokowane proaktywnie, często po 3–5 żądaniach.
2. Śledzenie odcisku TLS (JA3/JA4)
Nawet jeśli wyślesz poprawny nagłówek User-Agent, serwer może rozpoznać Twój klient po handshake TLS. Biblioteki takie jak requests czy httpx mają charakterystyczne szyfry i rozszerzenia, które różnią się od prawdziwej przeglądarki Chrome. Systemy anty-bot porównują odcisk TLS z deklarowanym UA — niezgodność to silny sygnał „bot”.
3. CAPTCHA po kilku żądaniach datacenter
W testach z adresów datacenter (bez proxy) Yelp zazwyczaj pozwala na 2–5 żądań do /biz/ przed pokazaniem CAPTCHA lub HTTP 429. Z proxy rezydencyjnym i odpowiednim tempem można utrzymać sesję na setkach żądań.
Dlaczego rotacyjne proxy rezydencyjne z geo-US są niezbędne
Adresy IP z puli datacenter są łatwo identyfikowalne — PerimeterX utrzymuje listy ASN (Autonomous System Numbers) dla głównych dostawców chmurowych. Adresy rezydencyjne pochodzą od dostawców ISP i wyglądają jak ruch prawdziwych użytkowników domowych.
Dodatkowo geo-targetowanie ma znaczenie dla wyników lokalnych. Yelp personalizuje niektóre wyniki wyszukiwania i rekomendacje na podstawie lokalizacji IP. Jeśli scrapujesz firmy w Austin, Texas, żądania z IP w USA — a najlepiej w Teksasie — zwracają bardziej spójne dane niż żądania z IP w Niemczech.
Przykład konfiguracji ProxyHat z geo-targetowaniem:
http://user-country-US-city-austin:pass@gate.proxyhat.com:8080
Ta konfiguracja kieruje ruch przez rezydencyjne IP w Austin. Dla innych miast zmień parametr city, np. city-san-francisco, city-new-york.
Strategia rotacji: używaj rotacji per-żądanie dla list firm (wyszukiwanie), ale sesji sticky (-session-) dla pobierania recenzji z jednej firmy — aby utrzymać ciasteczko _px3 i uniknąć ponownego wyzwania sensor.
Implementacja w Pythonie — review_feed i __INITIAL_STATE__
Strona /biz/<slug> osadza duży obiekt JSON w tagu <script> jako __INITIAL_STATE__. Zawiera on dane biznesowe, godziny, kategorie i fragmenty recenzji. Dodatkowo Yelp ładuje więcej recenzji przez endpoint /biz/<slug>/review_feed z parametrami rl (review limit) i start (offset).
Krok 1: Pobranie strony biznesu i ekstrakcja __INITIAL_STATE__
import requests
import json
import re
import time
import random
# ProxyHat — rotacyjne proxy rezydencyjne z geo US
proxy_url = "http://user-country-US-city-austin-session-yelp01:pass@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/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
}
slug = "gary-danko-san-francisco"
url = f"https://www.yelp.com/biz/{slug}"
resp = requests.get(url, headers=headers, proxies=proxies, timeout=30)
print(f"Status: {resp.status_code}")
if resp.status_code == 200:
# Szukaj __INITIAL_STATE__ w HTML
match = re.search(r"__INITIAL_STATE__\s*=\s*({.*?});", resp.text, re.DOTALL)
if match:
raw_json = match.group(1)
state = json.loads(raw_json)
# Nawigacja po strukturze — ścieżka może się zmieniać, sprawdzaj klucze
biz_data = state.get("bizDetailsPageProps", {}).get("businessDetails", {})
name = biz_data.get("name", "")
rating = biz_data.get("rating", 0)
review_count = biz_data.get("reviewCount", 0)
categories = [c.get("title", "") for c in biz_data.get("categories", [])]
print(f"Firma: {name}")
print(f"Ocena: {rating}/5 ({review_count} recenzji)")
print(f"Kategorie: {', '.join(categories)}")
# Pierwsze recenzje (obcięte)
reviews = biz_data.get("reviews", [])[:3]
for r in reviews:
print(f"---")
print(f"Autor: {r.get('author', {}).get('name', 'N/A')}")
print(f"Ocena: {r.get('rating', 'N/A')}")
text = r.get('comment', {}).get('text', '')[:200]
print(f"Tekst: {text}...")
else:
print("Nie znaleziono __INITIAL_STATE__")
else:
print(f"Zablokowane — status {resp.status_code}. Sprawdź proxy i UA.")
Uwaga: Struktura __INITIAL_STATE__ zmienia się między wersjami Yelp. Traktuj powyższy kod jako punkt wyjścia — zawsze sprawdzaj klucze w odpowiedzi przed parsowaniem masowym.
Krok 2: Paginacja recenzji przez review_feed
import requests
import json
import time
proxy_url = "http://user-country-US-session-yelp02:pass@gate.proxyhat.com:8080"
proxies = {"http": proxy_url, "https": proxy_url}
headers = {
"User-Agent": "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",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.yelp.com/biz/gary-danko-san-francisco",
}
slug = "gary-danko-san-francisco"
all_reviews = []
start = 0
batch_size = 20
max_reviews = 200
while start < max_reviews:
feed_url = f"https://www.yelp.com/biz/{slug}/review_feed?rl={batch_size}&start={start}"
try:
resp = requests.get(feed_url, headers=headers, proxies=proxies, timeout=30)
if resp.status_code == 200:
data = resp.json()
reviews = data.get("reviews", [])
if not reviews:
print(f"Brak recenzji przy start={start} — koniec.")
break
for r in reviews:
all_reviews.append({
"author": r.get("author", {}).get("name", ""),
"rating": r.get("rating", 0),
"date": r.get("date", ""),
"text": r.get("comment", {}).get("text", ""),
})
print(f"Pobrano {len(reviews)} recenzji (łącznie: {len(all_reviews)})")
start += batch_size
# Pacing — 2-4 sekundy między żądaniami
time.sleep(random.uniform(2.0, 4.0))
elif resp.status_code == 429:
print("Rate limit — czekam 30s...")
time.sleep(30)
else:
print(f"Status {resp.status_code} — przerywam.")
break
except Exception as e:
print(f"Błąd: {e}")
break
print(f"\nZbierano łącznie {len(all_reviews)} recenzji.")
Implementacja w Node.js przez SOCKS5 (port 1080)
Dla środowisk Node.js możesz użyć proxy SOCKS5 na porcie 1080. SOCKS5 działa na poziomie TCP i jest obsługiwany przez bibliotekę socks-proxy-agent.
const { SocksProxyAgent } = require('socks-proxy-agent');
const fetch = require('node-fetch');
// ProxyHat SOCKS5 — rezydencyjne, geo US, sesja sticky
const proxyUrl = 'socks5://user-country-US-session-node01:pass@gate.proxyhat.com:1080';
const agent = new SocksProxyAgent(proxyUrl);
const slug = 'gary-danko-san-francisco';
const url = `https://www.yelp.com/biz/${slug}`;
const headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
};
(async () => {
try {
const resp = await fetch(url, { agent, headers, timeout: 30000 });
console.log(`Status: ${resp.status}`);
if (resp.ok) {
const html = await resp.text();
const match = html.match(/__INITIAL_STATE__\s*=\s*({[\s\S]*?});/);
if (match) {
const state = JSON.parse(match[1]);
const biz = state?.bizDetailsPageProps?.businessDetails || {};
console.log(`Firma: ${biz.name || 'N/A'}`);
console.log(`Ocena: ${biz.rating || 'N/A'}/5`);
console.log(`Recenzji: ${biz.reviewCount || 0}`);
const reviews = (biz.reviews || []).slice(0, 3);
reviews.forEach(r => {
const author = r?.author?.name || 'N/A';
const text = (r?.comment?.text || '').slice(0, 150);
console.log(`- [${r.rating}★] ${author}: ${text}...`);
});
} else {
console.log('Nie znaleziono __INITIAL_STATE__');
}
} else {
console.log(`Zablokowane: ${resp.status}`);
}
} catch (err) {
console.error('Błąd:', err.message);
}
})();
Paginacja, pacing i zarządzanie sesjami proxy
Rotacja per-żądanie vs. sesje sticky
Rotacja per-żądanie (bez flagi -session-) przydaje się do scrapowania list wyników wyszukiwania — każde żądanie ma świeży IP, co rozprasza obciążenie reputacji. Sesje sticky (np. -session-yelp-biz-123) są lepsze do pobierania wielu stron recenzji z jednej firmy, ponieważ:
- Utrzymują ciasteczko
_px3dla tej samej pary IP–sesja. - Unikają ponownego wyzwania sensor PerimeterX.
- Zmniejszają ryzyko CAPTCHA mid-pagination.
Przykład sesji sticky dla jednej firmy:
http://user-country-US-session-biz-garydanko:pass@gate.proxyhat.com:8080
Po zakończeniu scrapowania danej firmy zmień nazwę sesji dla kolejnej.
Pacing i rate-limit
Yelp nie publikuje oficjalnych limitów dla scrapowania, ale empirycznie:
- 2–4 sekundy między żądaniami do tej samej firmy — bezpieczne tempo.
- 1–2 żądania na sekundę z jednego IP — górna granica przed pojawieniem się CAPTCHA.
- Po HTTP 429 odczekaj 30–60 sekund i zmień sesję proxy.
- Po HTTP 403 z treścią PerimeterX — odczekaj 5–10 minut i użyj nowego IP.
Rotacja User-Agent
Nie polegaj na jednym UA. Używaj puli 10–20 realnych ciągów Chrome/Firefox/Safari i rotuj je losowo. Upewnij się, że UA jest spójny z innymi nagłówkami — np. Chrome na Windows powinien wysyłać sec-ch-ua nagłówki.
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/123.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0",
# ... dodaj więcej
]
ua = random.choice(user_agents)
TLS fingerprint — zaawansowane
Dla produkcji wysokiej skali rozważ użycie bibliotek z możliwością modyfikacji odcisku TLS, takich jak curl-impersonate lub curl_cffi w Pythonie. Te biblioteki emulują handshake TLS przeglądarki Chrome, co znacznie zmniejsza ryzyko wykrycia przez systemy anty-bot oparte na JA3/JA4.
Konfiguracja ProxyHat i linki wewnętrzne
ProxyHat oferuje rotacyjne proxy rezydencyjne z geo-targetowaniem na poziomie kraju i miasta. Dla scrapowania Yelp rekomendujemy:
- Typ proxy: rezydencyjne (residential) — adresy ISP, wysoka reputacja.
- Geo:
country-USjako baza;city-dla konkretnych rynków lokalnych. - Port:
8080(HTTP) dla Pythonrequests;1080(SOCKS5) dla Node.js. - Sesje: sticky
-session-dla paginacji recenzji; rotacja dla list wyszukiwania.
Sprawdź ceny ProxyHat oraz dostępne lokalizacje proxy. Więcej o przypadkach użycia znajdziesz na stronach web scraping i SERP tracking. Pełną dokumentację techniczną znajdziesz na docs.proxyhat.com.
Etyczne scrapowanie i kiedy użyć oficjalnego API
Scrapowanie danych publicznych jest legalne w wielu jurysdykcjach, ale „publicznie dostępne” nie znaczy „wolne od ograniczeń”. Oto zasady, których trzymaj się w 2026:
1. Szanuj robots.txt
Sprawdź https://www.yelp.com/robots.txt przed rozpoczęciem. Jeśli Yelp wyraźnie blokuje ścieżkę /biz/ dla botów, scrapowanie tej ścieżki narusza jego intencje i może być traktowane jako nadużycie.
2. Dane osobowe a RODO (GDPR)
Recenzje Yelp zawierają imiona i nazwiska (lub pseudonimy) autorów oraz ich teksty — to dane osobowe w sensie RODO. Jeśli budujesz zbiór dla użytkowników w UE:
- Nie przechowuj danych identyfikujących autorów bez podstawy prawnej.
- Rozważ anonimizację (haszowanie nazw, usuwanie bezpośrednich identyfikatorów).
- Określ cel przetwarzania i okres retencji.
Więcej informacji znajdziesz na stronie Komisji Europejskiej — ochrona danych.
3. Unikaj treści za loginem
Nie próbuj omijać logowania, by uzyskać dostęp do treści, które Yelp celowo ukrywa dla niezalogowanych. To zwiększa ryzyko prawne (CFAA w USA) i etyczne.
4. Preferuj Fusion API tam, gdzie wystarcza
Jeśli potrzebujesz tylko podstawowych danych biznesowych (nazwa, adres, ocena, kategoria, max 3 recenzje), użyj oficjalnego Fusion API. Jest szybsze, legalne i nie wymaga infrastruktury proxy. Scrapowanie uzasadnij tylko wtedy, gdy Fusion API nie pokrywa Twojego przypadku użycia — np. pełna historia recenzji.
5. Pacing i obciążenie serwera
Utrzymuj rozsądne tempo (2–4 s między żądaniami) i nie wysyłaj setek równoległych żądań z jednego IP. Traktuj infrastrukturę Yelp z szacunkiem — to nie jest serwer do DDoS.
Najważniejsze wnioski (Key Takeaways)
- Publiczne dane Yelp — profile firm, oceny, kategorie, godziny, teksty recenzji — są dostępne bez logowania, ale chronione przez PerimeterX/HUMAN.
- Fusion API zwraca max 3 recenzje na firmę — scrapowanie uzasadnione tylko dla pełnej historii recenzji.
- Proxy rezydencyjne z geo-US (np.
country-US-city-austin) są niezbędne — adresy datacenter są blokowane po 3–5 żądaniach.- Sesje sticky (
-session-) utrzymują ciasteczko_px3i zmniejszają ryzyko CAPTCHA podczas paginacji.- Parsing
__INITIAL_STATE__daje strukturalne dane bez dodatkowych żądań;/review_feedsłuży do paginacji.- Tempo 2–4 s między żądaniami i rotacja UA to minimum dla stabilnego scrapowania.
- Etyka i prawo — sprawdzaj robots.txt, anonimizuj dane osobowe (RODO), preferuj Fusion API tam, gdzie wystarcza.
Często zadawane pytania (FAQ)
Czy scrapowanie Yelp jest legalne?
Scrapowanie publicznie dostępnych danych nie jest jednoznacznie nielegalne, ale może naruszać Warunki Korzystania z Usług Yelp. W USA nadużycia mogą podlegać ustawie CFAA, a w UE recenzje zawierające dane osobowe podlegają RODO. Zawsze konsultuj się z prawnikiem i rozważ oficjalne Fusion API jako pierwszą opcję.
Jakie proxy najlepiej sprawdzają się do scrapowania Yelp?
Najlepiej sprawdzają się rotacyjne proxy rezydencyjne z geo-targetowaniem na USA. Adresy datacenter są szybko blokowane przez PerimeterX (często po 3–5 żądaniach). Proxy rezydencyjne z flagą country-US i opcjonalnie city- wyglądają jak ruch prawdziwych użytkowników i pozwalają na stabilne pobieranie danych.
Jak unikać blokad PerimeterX przy scrapowaniu Yelp?
Używaj proxy rezydencyjnych z sesjami sticky (-session-), utrzymuj tempo 2–4 sekundy między żądaniami, rotuj nagłówki User-Agent z puli realnych przeglądarek, i rozważ biblioteki modyfikujące odcisk TLS (np. curl_cffi). Po HTTP 429 odczekaj 30–60 s i zmień sesję proxy. Po HTTP 403 od PerimeterX odczekaj 5–10 minut.
Ile recenzji mogę pobrać z jednej firmy na Yelp?
Oficjalne Fusion API zwraca maksymalnie 3 recenzje na firmę. Scrapowanie strony /biz/<slug> i endpointu /review_feed pozwala na pobranie wszystkich publicznie widocznych recenzji — często kilkuset. Wymaga to jednak paginacji z parametrami rl i start oraz odpowiedniego pacingu.
Czym jest __INITIAL_STATE__ na stronie Yelp?
__INITIAL_STATE__ to duży obiekt JSON osadzony w tagu <script> na stronie biznesu Yelp. Zawiera strukturalne dane: nazwę firmy, ocenę, kategorie, godziny otwarcia i początkowy zestaw recenzji. Ekstrakcja tego obiektu regexem lub parserem HTML pozwala uniknąć dodatkowych żądań API i uzyskać czyste dane w jednym żądaniu.






