Ważne zastrzeżenie prawne: Ten artykuł dotyczy wyłącznie dostępu do publicznie dostępnych danych na Yelp. Przed rozpoczęciem scrapowania zapoznaj się z plikiem robots.txt Yelp oraz Regulaminem Yelp (Terms of Service). W Stanach Zjednoczonych Computer Fraud and Abuse Act (CFAA) ogranicza nieautoryzowany dostęp do systemów komputerowych — zapoznaj się z tekstem CFAA. W Unii Europejskiej RODO (GDPR) chroni dane osobowe, w tym opinie użytkowników zawierające identyfikowalne informacje. Scrapowanie treści objętych logowaniem lub naruszające regulamin platformy może być niezgodne z prawem.
Scrapowanie Yelp w 2026: co jest publicznie dostępne bez logowania
Scrapowanie Yelp — czyli pobieranie danych biznesowych Yelp — pozostaje jednym z najczęstszych zadań dla zespołów budujących zbiory danych o lokalnych firmach. Yelp udostępnia publicznie, bez logowania, znaczną część informacji biznesowych: nazwę firmy, adres, numer telefonu, kategorie, godziny otwarcia, ocenę (gwiazdki) oraz liczbę opinii. Profile firm dostępne są pod adresem /biz/<slug>, np. yelp.com/biz/torchys-tacos-austin.
Dane dostępne publicznie bez logowania obejmują:
- Profil biznesowy: nazwa, adres, telefon, strona WWW, kategorie, godziny otwarcia, atrybuty (np. „dostępne WiFi”, „parking”).
- Ocena i licznik opinii: ocena w gwiazdkach (1–5) oraz łączna liczba opinii.
- Teksty opinii: pierwsze ~3–5 opinii widocznych na stronie profilu (reszta wymaga paginacji lub logowania).
- Współrzędne geograficzne: szerokość i długość geograficzna osadzone w strukturze JSON na stronie.
Yelp oferuje również oficjalne API — Yelp Fusion API — które zwraca do 3 opinii na zapytanie dla danego biznesu. To ograniczenie sprawia, że Fusion API nie wystarcza do budowania pełnych zbiorów danych opinii, co często skłania programistów do scrapowania stron profilowych.
Kluczowa decyzja: jeśli potrzebujesz tylko podstawowych danych biznesowych (nazwa, adres, ocena, kategorie), Fusion API jest wystarczające i bezpieczniejsze. Jeśli potrzebujesz pełnych tekstów opinii lub paginacji, scrapowanie publicznych stron jest jedyną opcją — ale wymaga ostrożności i proxy.
Dlaczego scrapowanie Yelp jest trudne: PerimeterX i HUMAN
Yelp chroni swoje strony przed botami za pomocą PerimeterX (obecnie HUMAN Security) — systemu ochrony botów działającego na warstwie przeglądarki i sieci. PerimeterX stosuje kilka mechanizmów, które skutecznie blokują naивные scrapery:
Mechanizmy obronne PerimeterX
- Cookie
_px3: Token sesyjny PerimeterX generowany przez JavaScript. Scraper bez możliwości wykonania JS nie otrzyma tego ciasteczka i zostanie zablokowany już po 2–3 żądaniach z adresu IP centrum danych. - Wyzwanie sensor (sensor challenge): PerimeterX zbiera dane z czujników przeglądarki (canvas fingerprint, WebGL, czcionki, ruch myszy) i wysyła je w zaszyfrowanym ładunku. Brak tych danych oznacza natychmiastową blokadę.
- Reputacja IP: Adresy IP z zakresów centrów danych (AWS, GCP, DigitalOcean) mają bardzo niską reputację. Po ~3–5 żądaniach z takiego IP, PerimeterX zwraca stronę z CAPTCHA lub błędem 403.
- TLS fingerprinting (JA3/JA4): PerimeterX analizuje parametry handshake TLS. Biblioteki takie jak
requestsczyaxiosmają charakterystyczne odciski TLS, różne od prawdziwych przeglądarek.
W praktyce oznacza to, że prosty skrypt requests.get('https://www.yelp.com/biz/...') z adresu IP centrum danych zostanie zablokowany w ciągu pierwszych 5 żądań. To właśnie dlatego proxy residential są niezbędne do scrapowania Yelp w skali produkcyjnej.
Dlaczego proxy residential z geo-US są kluczowe
Yelp to platforma skoncentrowana głównie na rynku amerykańskim. Wyniki wyszukiwania lokalnego i sortowanie firm zależą od lokalizacji geograficznej użytkownika. Jeśli Twoje żądanie pochodzi z IP w Niemczech, Yelp może zwrócić inne wyniki lub ograniczyć dostęp do niektórych funkcji.
Adresy IP residential (pochodzące od dostawców internetu dla gospodarstw domowych) mają znacznie wyższą reputację w systemie PerimeterX niż adresy centrów danych. Rotacja adresów IP pozwala rozproszyć żądania na wiele „tożsamości”, obniżając ryzyko blokady.
Kluczowe parametry proxy dla scrapowania Yelp:
| Parametr | Wartość | Dlaczego |
|---|---|---|
| Typ proxy | Residential | Wysoka reputacja IP w PerimeterX; niski wskaźnik blokad (<5% vs >80% dla datacenter) |
| Geo-targeting | US (country-US) | Lokalne wyniki biznesowe; zgodność z rynkiem Yelp |
| Rotacja | Per-request lub sticky session | Rotacja obniża ryzyko; sticky zachowuje sesję PerimeterX |
| Concurrent sessions | 50–100 | Równoległość bez przekraczania limitów bezpieczeństwa |
Implementacja: Python — pobieranie opinii przez ProxyHat
Poniższy przykład pokazuje, jak pobrać publiczny profil biznesowy Yelp z wykorzystaniem proxy residential ProxyHat. Skrypt łączy się przez bramę HTTP gate.proxyhat.com:8080 z geo-targetingiem na Austin, TX, i sesją sticky.
import requests
import json
import re
import time
import random
# ProxyHat — residential proxy z geo-US i sticky session
proxy_url = "http://user-country-US-city-austin-session-yelp001:PASSWORD@gate.proxyhat.com:8080"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
# Rotacja User-Agent (prawdziwe przeglądarki)
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 (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/130.0.0.0 Safari/537.36",
]
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",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
}
business_slug = "torchys-tacos-austin"
url = f"https://www.yelp.com/biz/{business_slug}"
try:
response = requests.get(url, headers=headers, proxies=proxies, timeout=30)
response.raise_for_status()
# Yelp osadza dane w tagu script jako __INITIAL_STATE__ lub w bloku JSON
# Szukamy wzorca "__INITIAL_STATE__" lub bizDetailsPage
state_match = re.search(
r'<script[^>]*>\s*window\.__INITIAL_STATE__\s*=\s*({.*?});?\s*</script>',
response.text,
re.DOTALL
)
if state_match:
raw_json = state_match.group(1)
# Próba parsowania (często obcięte lub zawiera nieprawidłowy JS)
try:
state_data = json.loads(raw_json)
biz = state_data.get("bizDetailsPage", {}).get("businessDetails", {})
print(f"Nazwa: {biz.get('name', 'N/A')}")
print(f"Ocena: {biz.get('rating', 'N/A')}")
print(f"Liczba opinii: {biz.get('reviewCount', 'N/A')}")
reviews = biz.get("reviews", [])
for review in reviews[:3]:
print(f"--- Opinia ---")
print(f"Autor: {review.get('author', {}).get('name', 'N/A')}")
print(f"Ocena: {review.get('rating', 'N/A')}")
text = review.get('comment', {}).get('text', '')
print(f"Tekst: {text[:200]}...") # obcięty tekst
except json.JSONDecodeError:
print("Nie udało się sparsować __INITIAL_STATE__ — spróbuj alternatywnej metody")
else:
print("Nie znaleziono __INITIAL_STATE__ — możliwa blokada PerimeterX")
# Sprawdź czy odpowiedź to strona CAPTCHA
if "px-captcha" in response.text.lower():
print("Zablokowane przez PerimeterX CAPTCHA")
except requests.exceptions.RequestException as e:
print(f"Błąd żądania: {e}")
# Pacing: odczekaj 2-5 sekund między żądaniami
time.sleep(random.uniform(2, 5))
Powyższy skrypt demonstruje kluczowe wzorce:
- Geo-targeting:
user-country-US-city-austinzapewnia, że wyniki są lokalizowane na Austin, TX. - Sesja sticky:
session-yelp001utrzymuje ten sam adres IP dla wielu żądań, co jest kluczowe, ponieważ cookie_px3jest powiązane z IP. - Rotacja User-Agent: Trzy realistyczne nagłówki UA zmniejszają ryzyko wykrycia przez fingerprinting.
- Pacing: Losowe opóźnienie 2–5 sekund między żądaniami naśladuje ludzkie zachowanie.
Pobieranie opinii przez review_feed (JSON)
Yelp ładuje dodatkowe opinie asynchronicznie przez endpoint /biz/. Ten endpoint zwraca JSON z opiniami paginowanymi po parametrze rl (review language / offset):
def fetch_reviews(business_slug, start=0, proxy_url=None):
"""Pobierz opinie przez Yelp review_feed endpoint."""
feed_url = f"https://www.yelp.com/biz/{business_slug}/review_feed?rl={start}&sort_by=relevance_desc"
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
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": "application/json",
"Referer": f"https://www.yelp.com/biz/{business_slug}",
"X-Requested-With": "XMLHttpRequest",
}
resp = requests.get(feed_url, headers=headers, proxies=proxies, timeout=30)
if resp.status_code == 200:
data = resp.json()
reviews = data.get("reviews", [])
print(f"Pobrano {len(reviews)} opinii (offset: {start})")
for r in reviews:
print(f" [{r.get('rating')}★] {r.get('user', {}).get('name', 'N/A')}: {r.get('comment', {}).get('text', '')[:100]}...")
return reviews
elif resp.status_code == 403:
print("Zablokowane (403) — rotacja IP lub obniżenie tempa")
return []
else:
print(f"Nieoczekiwany status: {resp.status_code}")
return []
# Przykład paginacji
proxy = "http://user-country-US-session-yelp002:PASSWORD@gate.proxyhat.com:8080"
all_reviews = []
for offset in range(0, 100, 20): # 5 stron po 20 opinii
batch = fetch_reviews("torchys-tacos-austin", start=offset, proxy_url=proxy)
if not batch:
break
all_reviews.extend(batch)
time.sleep(random.uniform(3, 6)) # pacing 3-6s
Implementacja: Node.js — proxy SOCKS5 przez ProxyHat
Dla środowisk Node.js, ProxyHat obsługuje również SOCKS5 na porcie 1080. Poniższy przykład używa biblioteki socks-proxy-agent:
const { SocksProxyAgent } = require('socks-proxy-agent');
const axios = require('axios');
// ProxyHat SOCKS5 — residential, geo-US, sticky session
const socksUrl = 'socks5://user-country-US-session-yelp003:PASSWORD@gate.proxyhat.com:1080';
const agent = new SocksProxyAgent(socksUrl);
const userAgents = [
'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 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
];
async function scrapeYelpBiz(slug) {
const url = `https://www.yelp.com/biz/${slug}`;
const config = {
url,
httpsAgent: agent,
timeout: 30000,
headers: {
'User-Agent': userAgents[Math.floor(Math.random() * userAgents.length)],
'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',
},
};
try {
const response = await axios(config);
// Szukaj __INITIAL_STATE__ w HTML
const match = response.data.match(
/window\.__INITIAL_STATE__\s*=\s*({[\s\S]*?});?\s*<\/script>/
);
if (match) {
const rawJson = match[1];
try {
const state = JSON.parse(rawJson);
const biz = state?.bizDetailsPage?.businessDetails || {};
console.log(`Nazwa: ${biz.name || 'N/A'}`);
console.log(`Ocena: ${biz.rating || 'N/A'}`);
console.log(`Liczba opinii: ${biz.reviewCount || 'N/A'}`);
console.log(`Telefon: ${biz.phone || 'N/A'}`);
console.log(`Adres: ${JSON.stringify(biz.location || {})}`);
const reviews = biz.reviews || [];
reviews.slice(0, 3).forEach((r, i) => {
console.log(`\n--- Opinia ${i + 1} ---`);
console.log(`Autor: ${r?.author?.name || 'N/A'}`);
console.log(`Ocena: ${r?.rating || 'N/A'}`);
console.log(`Tekst: ${(r?.comment?.text || '').substring(0, 150)}...`);
});
} catch (e) {
console.error('Błąd parsowania JSON:', e.message);
}
} else {
console.log('Nie znaleziono __INITIAL_STATE__');
if (response.data.toLowerCase().includes('px-captcha')) {
console.log('Zablokowane przez PerimeterX CAPTCHA');
}
}
} catch (error) {
console.error('Błąd żądania:', error.message);
}
}
// Uruchom z pacingiem
(async () => {
await scrapeYelpBiz('torchys-tacos-austin');
await new Promise(r => setTimeout(r, 3000 + Math.random() * 2000));
})();
Paginacja, rate-limit pacing i sesje sticky
Skuteczny scraper Yelp musi balansować między szybkością a niezawodnością. Oto kluczowe strategie produkcyjne:
Paginacja opinii
Endpoint review_feed zwraca ~20 opinii na żądanie. Parametr rl kontroluje offset. Paginacja powinna być stopniowa — nagły skok z offsetu 0 do 200 wygląda podejrzanie dla PerimeterX.
Rate-limit pacing
Rekomendowane tempo: 1 żądanie na 3–6 sekund na sesję IP. Przy 50 równoległych sesjach sticky osiągasz ~10 żądań/sekundę, co pozwala pobrać ~36 000 opinii na godzinę. Wyższe tempo znacząco zwiększa ryzyko blokad.
Sesje sticky — kiedy i dlaczego
Cookie _px3 PerimeterX jest powiązane z adresem IP. Jeśli zmienisz IP w środku sesji, PerimeterX uzna to za podejrzane i może zażądać CAPTCHA. Dlatego:
- Używaj sticky session (
-session-abc123) dla wszystkich żądań do jednej firmy (profil + paginacja opinii). - Zmieniaj sesję (nowy identyfikator) przy przejściu do kolejnej firmy.
- Utrzymuj jedną sesję przez maksymalnie 10–15 minut lub ~50 żądań — potem rotuj.
Rotacja User-Agent i nagłówków
Używaj zestawu realistycznych, aktualnych User-Agentów (Chrome, Firefox, Safari — wersje z ostatnich 6 miesięcy). Nie używaj przestarzałych stringów jak Python/3.9 czy Mozilla/5.0 (compatible; bot/1.0). Utrzymuj spójność: jeśli UA mówi Chrome na Windows, nagłówki Accept i Sec-CH-UA powinny być zgodne.
ProxyHat: konfiguracja i integracja
ProxyHat oferuje proxy residential, mobile i datacenter z globalnym geo-targetingiem. Dla scrapowania Yelp rekomendowane są proxy residential z geo-US. Konfiguracja jest prosta — wszystkie parametry (kraj, miasto, sesja) przekazywane są w nazwie użytkownika.
Formaty połączenia ProxyHat:
| Protokół | URL | Port |
|---|---|---|
| HTTP | http://user-country-US:PASSWORD@gate.proxyhat.com:8080 |
8080 |
| SOCKS5 | socks5://user-country-US:PASSWORD@gate.proxyhat.com:1080 |
1080 |
| HTTP + city | http://user-country-US-city-austin:PASSWORD@gate.proxyhat.com:8080 |
8080 |
| HTTP + session | http://user-session-abc123:PASSWORD@gate.proxyhat.com:8080 |
8080 |
Sprawdź ceny ProxyHat oraz dostępne lokalizacje. Więcej przykładów integracji znajdziesz w dokumentacji ProxyHat.
Etyczne scrapowanie i kiedy używać oficjalnego API
Scrapowanie Yelp powinno być zawsze przeprowadzane z poszanowaniem prawnej i etycznym. Oto zasady, których należy przestrzegać:
- Szanuj robots.txt: Sprawdź yelp.com/robots.txt przed rozpoczęciem. Jeśli dana ścieżka jest wykluczona, nie scrapuj jej.
- Nie pobieraj danych osobowych: Opinie Yelp zawierają nazwy użytkowników, zdjęcia profilowe i teksty, które mogą zawierać dane osobowe. Zgodnie z RODO (GDPR), przetwarzanie tych danych wymaga podstawy prawnej. Jeśli budujesz zbiór danych do analizy rynkowej, rozważ anonimizację (usunięcie nazw użytkowników, hashowanie identyfikatorów).
- Nie omijaj logowania: Jeśli treść jest dostępna tylko po zalogowaniu, nie używaj sztucznych kont ani nie omijaj mechanizmów autoryzacji. To może naruszać CFAA.
- Preferuj Fusion API tam, gdzie wystarcza: Jeśli potrzebujesz tylko podstawowych danych biznesowych (nazwa, adres, ocena, kategorie, telefon), Yelp Fusion API jest bezpieczniejszą i legalną opcją. Fusion API zwraca do 3 opinii na biznes — jeśli to wystarcza, nie scrapuj.
- Ogranicz tempo: Nie przeciążaj serwerów Yelp. Tempo 1 żądania/3–6 sekund na sesję jest rozsądne. Agresywne scrapowanie może zostać uznane za atak DoS.
- Używaj danych odpowiedzialnie: Nie redistribuuj pobranych danych bez licencji. Yelp posiada prawa autorskie do swoich treści.
Złota zasada: jeśli Fusion API pokrywa 80% Twoich potrzeb — używaj go. Scrapuj tylko te 20%, których API nie dostarcza (pełne teksty opinii, paginacja, dane osadzone w HTML).
Najczęstsze błędy i pułapki
- Używanie proxy datacenter — PerimeterX blokuje adresy centrów danych po 3–5 żądaniach. Wskaźnik sukcesu spada poniżej 20%.
- Brak sesji sticky — Zmiana IP w środku sesji powoduje utratę cookie
_px3i natychmiastową blokadę. - Zbyt szybkie tempo — 10 żądań/sekundę z jednego IP = gwarantowana blokada. Trzymaj 1 żądanie/3–6s.
- Ignorowanie TLS fingerprinting — Biblioteka
requestsma charakterystyczny JA3. Rozważ użyciecurl_cffilubtls-clientdo naśladowania przeglądarki. - Parsing HTML z regex — Struktura
__INITIAL_STATE__może się zmieniać. Używaj odpornego parsowania JSON z fallbackiem.
Kluczowe wnioski (Key Takeaways)
- Yelp udostępnia publicznie dane biznesowe (nazwa, adres, ocena, ~3 opinii) bez logowania — reszta wymaga scrapowania lub Fusion API (limit 3 opinii).
- PerimeterX/HUMAN blokuje scrapery z IP centrów danych po 3–5 żądaniach — proxy residential są niezbędne.
- Geo-targeting US (country-US) zapewnia lokalne wyniki biznesowe i wyższą reputację IP.
- Sesje sticky utrzymują ciągłość cookie
_px3— zmieniaj sesję przy przejściu do nowej firmy.- Tempo 1 żądanie/3–6 sekund na sesję + 50 równoległych sesji = ~36 000 opinii/godzinę z wskaźnikiem sukcesu >90%.
- Preferuj Fusion API, gdy wystarcza 3 opinii na biznes — to legalna i stabilna opcja.
Gotowy na budowę zbioru danych Yelp? Zacznij od przypadku użycia web scraping i planów cenowych ProxyHat. Jeśli potrzebujesz monitorowania wyników wyszukiwania, sprawdź również SERP tracking.






