Jak zbierać dane z Yelp w Pythonie bez blokad

Ostatnia aktualizacja: April 15, 2026
Jak zbierać dane z Yelp w Pythonie bez blokad

Yelp zawiera 330 milionów łącznych recenzji na 8,4 miliona aktywnych profili firm — a wyciągnięcie tych danych do wygodnego formatu jeszcze nigdy nie było tak trudne. W latach 2024–2025 Yelp mocno zaostrzył walkę z botami, przez co większość dotychczasowych poradników o scrapowaniu w Pythonie po prostu cicho przestała działać.

Jeśli ostatnio próbowałeś uruchomić scraper do Yelp i wpadłeś w serię błędów 403, pustych odpowiedzi HTML albo CAPTCHA, których pół roku temu jeszcze nie było, to nie wymysł. Yelp dziś używa fingerprintingu TLS/JA3, rotujących i zaciemnionych nazw klas CSS oraz agresywnej oceny reputacji IP — co oznacza, że stary sposób requests + BeautifulSoup, nadal polecany w większości poradników, wywraca się już przy pierwszym żądaniu. Spędziłem tygodnie na testowaniu różnych podejść pod aktualne zabezpieczenia Yelp i ten przewodnik obejmuje wszystko, co naprawdę działa w 2025 roku: oficjalne Fusion API (i dlaczego prawdopodobnie nie wystarczy), kompletny workflow scrapowania w Pythonie z wielowarstwową strategią antyblokową oraz 2‑klikową alternatywę no-code z Thunderbit dla osób, które po prostu chcą danych bez maratonu debugowania.

Wypróbuj Thunderbit do scrapowania Yelp

Po co scrapować Yelp w Pythonie i kto naprawdę na tym korzysta

Zanim napiszesz choćby jedną linię kodu, warto odpowiedzieć sobie na pytanie: jaki właściwie jest biznesowy sens danych z Yelp? Ta platforma to nie tylko serwis z recenzjami restauracji — to w praktyce żywa baza lokalnych firm, zawierająca uporządkowane dane kontaktowe, oceny, kategorie, godziny otwarcia i setki milionów opinii klientów.

yelp_stats_bd6a43108e.png

Oto, kto korzysta na tym najbardziej i jakie dane najczęściej pobiera:

Przypadek użyciaNajważniejsze pola danychDlaczego to ma znaczenie
Sprzedaż i lead generationnazwa firmy, telefon, strona, adres, kategoria, ocenaBudowanie precyzyjnych list potencjalnych klientów z sektora lokalnych MŚP — 4 na 5 użytkowników Yelp jest gotowych do zakupu już po wejściu na platformę
Analiza konkurencjirecenzje, oceny gwiazdkowe, liczba opinii, sentymentMonitorowanie reputacji konkurentów, wykrywanie braków w obsłudze, śledzenie trendów
Badania rynku i NLPpełny tekst recenzji, daty, metadane recenzentówAnaliza sentymentu, modelowanie tematów — recenzje Yelp są jednym z najczęściej używanych korpusów NLP w badaniach akademickich
Nieruchomości i wybór lokalizacjizagęszczenie firm, mix kategorii, jakość recenzji według obszaruWybór lokalizacji dla sieci i retailu — Yelp sprzedaje Location Intelligence jako licencjonowany produkt B2B dokładnie do tego celu
E-commerce i operacjesygnały cenowe, skargi klientów, godziny obsługiMonitorowanie, jak oceniani są konkurenci, wykrywanie wzorców operacyjnych

Wspólny mianownik jest prosty: prawdziwym celem są dane strukturalne, a Python jest tylko jednym ze sposobów dotarcia do nich. Część czytelników będzie chciała pełnej kontroli programistycznej. Inni po prostu potrzebują arkusza z kontaktami do hydraulików w Austin. Oba scenariusze opisuję poniżej.

Yelp Fusion API vs scrapowanie w Pythonie: co wybrać?

Większość poradników w ogóle pomija ten wybór i od razu przechodzi do kodu, nie sprawdzając, czy oficjalne Yelp Fusion API (dziś przemianowane na „Yelp Places API”) nie wystarczyłoby do celu. Z mojego doświadczenia taka analiza oszczędza godziny zmarnowanej pracy — bo API jest świetne do jednych rzeczy, a zupełnie bezużyteczne do innych.

Co naprawdę daje Fusion API

Fusion API udostępnia uporządkowane wyszukiwanie firm, szczegóły biznesowe, autouzupełnianie i endpoint z recenzjami. Jest oficjalne, dobrze opisane i nie wymaga obchodzenia zabezpieczeń antybotowych.

Problem zaczyna się przy endpointcie z recenzjami. Oto, co potwierdzili pracownicy Yelp na GitHubie:

„Yelp API nie zwraca pełnego tekstu recenzji. Domyślnie udostępniane są trzy fragmenty recenzji po 160 znaków.” — odpowiedź pracownika Yelp, GitHub Issue #163

To nie błąd — to założenie projektu. API fizycznie ogranicza się do 3 fragmentów recenzji (7 w planie Premium), każdy ucięty do około 160 znaków. Brakuje metadanych recenzji (głosów useful/funny/cool), historii recenzenta i odpowiedzi właściciela. Do tego dzienny limit dla nowych klientów spadł po maju 2023 do 300–500 wywołań dziennie — wcześniej było to 5 000. Cennik startuje od $29/miesiąc.

Ramy decyzyjne

CzynnikYelp Fusion APIScrapowanie w PythonieThunderbit (no-code)
Pełne recenzje❌ Tylko 3 fragmenty (~160 znaków każdy)✅ Wszystkie recenzje przez GraphQL✅ Wszystkie widoczne recenzje
Limity zapytań300–500/dzień (nowi); 5 000 (legacy)Zarządzane samodzielnie (koszt proxy)Model kredytowy
Czas konfiguracji~15 min (klucz API + SDK)Od kilku godzin do kilku dni~2 minuty
Pola biznesowe~20 pól strukturalnychNielimitowane (HTML/JSON)Pola sugerowane przez AI
Obsługa antybotaN/D (oficjalne)Trzeba zbudować samemuObsługiwane automatycznie
Ryzyko prawne✅ Oficjalne⚠️ Szara strefa ToS⚠️ Jak w przypadku scrapowania
Kosztminimum $29/mies.Darmowe (+ proxy $0.75–$4/GB)Dostępny darmowy plan
UtrzymanieNiskie (API stabilne)Wysokie (selektory się psują, antybot się zaostrza)Niskie (AI dostosowuje się ponownie)

Wybierz Fusion API, jeśli: potrzebujesz podstawowych informacji o firmie, małych jednorazowych lookupów albo oficjalnej integracji — i wystarczą Ci 3 fragmenty recenzji na firmę.

Wybierz scrapowanie w Pythonie, jeśli: potrzebujesz pełnego tekstu recenzji, wszystkich opinii dla danej firmy, metadanych recenzji, więcej niż 240 wyników na wyszukiwanie albo budżet masz niższy niż $29/miesiąc.

Wybierz Thunderbit, jeśli: chcesz szybko dostać dane bez pisania i utrzymywania kodu. O tym więcej w sekcji no-code poniżej.

No-code shortcut: scrapowanie Yelp z Thunderbit (bez Pythona)

Zanim przejdziemy do głębokiego nurkowania w Pythonie, oto najszybsza ścieżka dla osób, których celem są dane, a nie ćwiczenie programistyczne. Każdy konkurencyjny poradnik zakłada znajomość Pythona, ale w mojej pracy w Thunderbit widzę, że ogromna część osób wpisujących „scrape Yelp” to handlowcy, menedżerowie operacyjni i właściciele małych firm, którzy po prostu chcą arkusz z lokalnymi biznesami — a nie kursu fingerprintingu TLS.

Thunderbit ma już gotowe szablony dla Yelp:

  • Yelp Business Web Scraper — pobiera nazwę firmy, ocenę, dane kontaktowe, adres, godziny, kategorię
  • Yelp Review Scraper — pobiera nazwę użytkownika recenzenta, treść recenzji, ocenę, datę i lokalizację recenzenta

Jak to działa w praktyce

  1. Otwórz stronę wyników wyszukiwania Yelp albo stronę firmy w Chrome
  2. Kliknij AI Suggest Fields w rozszerzeniu Thunderbit — AI odczyta stronę i zaproponuje kolumny (nazwa firmy, ocena, liczba recenzji, przedział cenowy, kategoria, adres, telefon, URL)
  3. Kliknij Scrape — gotowe

W przypadku gotowych szablonów Yelp jest jeszcze prościej: otwierasz szablon i klikasz Scrape.

Scrapowanie podstron automatycznie obsługuje etap wzbogacania danych — zaczynasz od strony wyników Yelp, włączasz scraping podstron, a Thunderbit odwiedza każdą stronę firmy, aby pobrać godziny, pełne recenzje, stronę internetową, zdjęcia i udogodnienia. Bez dodatkowej konfiguracji.

Paginacja działa automatycznie — zarówno przy klikaniu, jak i przewijaniu, bez dodatkowych ustawień. (Więcej o tym, jak to działa, znajdziesz w naszym przewodniku po paginacji.)

Eksport jest darmowy na każdym planie — Excel, Google Sheets, Airtable, Notion, CSV, JSON. Bez pandas, bez kodu do zapisu CSV.

Porównanie czasu

CzasScraper w PythonieThunderbit
Pierwsze uruchomienieOd kilku godzin do kilku dni (selektory, paginacja, proxy, retry)Około 30 sekund z gotowym szablonem Yelp
Gdy Yelp zmienia markupRęczne przepisywanie selektorówPonowne kliknięcie AI Suggest Fields — automatyczne dostosowanie
Gdy IP zostanie zablokowaneDebugowanie, rotacja pul proxy, ponowne testyTryb cloud obsługuje rotację IP
Eksport do Google SheetsNapisać OAuth i kod łączący z pandasJedno kliknięcie, za darmo

Jeśli przetestujesz Thunderbit najpierw i uznasz, że wystarcza, możesz pominąć resztę artykułu. Jeśli potrzebujesz pełnej kontroli programistycznej, własnych pól lub skali większej niż kilka tysięcy rekordów miesięcznie — czytaj dalej.

Biblioteki Pythona do scrapowania Yelp: którą wybrać?

„Czy użyć Scrapy, BS4+requests czy Selenium?” to jedno z najczęstszych pytań w wątkach r/webscraping dotyczących Yelp. A jednak każdy poradnik po prostu wybiera ulubioną bibliotekę i idzie dalej, bez wyjaśnienia dlaczego. Oto uczciwy podział.

Rzeczywistość 2025: requests + BeautifulSoup nie działa na Yelp

Zestaw, który poleca każdy klasyczny poradnik do Yelp — pip install requests beautifulsoup4zostaje zablokowany przy pierwszym żądaniu w 2025 roku. Nie przy pięćdziesiątym. Przy pierwszym.

Powód: biblioteka Pythona requests wysyła fingerprint TLS/JA3, który nie odpowiada żadnej prawdziwej przeglądarce. Warstwa antybota Yelp wykrywa to już na etapie handshake TLS, zanim w ogóle odczyta nagłówek User-Agent. Testowałem to wielokrotnie — świeże IP, realistyczne nagłówki, losowe opóźnienia — i mimo to natychmiast dostawałem 403 Forbidden przy zwykłym requests.

Macierz wyboru biblioteki

BibliotekaNajlepsza doObsługuje JS?Antybot?Krzywa naukiSzybkość
requests + BeautifulSoupProste scrapowanie jednej strony (dla Yelp nie działa)Bardzo niskaSzybka (dopóki nie zostanie zablokowana)
httpx async + parselDuże, asynchroniczne scrapowanieNiskaBardzo szybka
curl_cffi + parselSpecyficznie Yelp: imitacja TLS✅ TLS/JA3/HTTP2NiskaBardzo szybka
Scrapy 2.14Pełne pipeline’y z paginacjąCzęściowo (przez scrapy-playwright)AutoThrottle, retry middlewareŚrednia-wysokaSzybka
Selenium 4.43 / Playwright 1.58Strony mocno oparte na JS, obejścia CAPTCHACzęściowoŚredniaWolna (~10–30 stron/min)
ThunderbitOsoby nietechniczne, szybka ekstrakcja✅ (przeglądarka)Wbudowane (tryb Cloud)Bardzo niskaSzybka

Odkrycie z curl_cffi

Biblioteką, która zmieniła mój workflow scrapowania Yelp, jest curl_cffi — Pythonowy binding do curl-impersonate. Generuje dokładnie taki sam fingerprint TLS/JA3 + HTTP/2 jak prawdziwy Chrome, a jego API jest praktycznie zamiennikiem requests:

from curl_cffi import requests

r = requests.get(
    "https://www.yelp.com/biz/some-restaurant",
    impersonate="chrome131",
)
print(r.status_code, len(r.text))

Ta jedna zmiana — from curl_cffi import requests oraz impersonate="chrome131" — omija największą warstwę antybota Yelp bez uruchamiania przeglądarki. W moich testach to różnica między natychmiastowym 403 a czystą odpowiedzią 200.

Polecany stack do Yelp w 2025 roku: curl_cffi + parsel + jmespath + residential proxies. Jeśli potrzebujesz pełnego pipeline’u z harmonogramem, owiń to w Scrapy 2.14 i użyj middleware downloadera opartego na curl_cffi.

Konfiguracja środowiska Pythona do scrapowania Yelp

  • Poziom trudności: średni
  • Czas potrzebny: około 15 minut na konfigurację, 1–2 godziny na działającego scrapera
  • Czego potrzebujesz: Python 3.10+ (zalecany 3.12), terminal i opcjonalnie dostawca residential proxy

Krok 1: Utwórz środowisko wirtualne i zainstaluj pakiety

python3.12 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install "curl_cffi>=0.11" "parsel>=1.9" "jmespath>=1.0" pandas

Co robi każdy pakiet:

  • curl_cffi — wysyła żądania HTTP z fingerprintem TLS Chrome’a (obejście antybota)
  • parsel — selektory CSS/XPath do parsowania HTML (ten sam silnik co Scrapy, ale lżejszy)
  • jmespath — deklaratywne zapytania do JSON (czytelniejsze niż zagnieżdżone odwołania do słowników w JSON-ie Yelp)
  • pandas — eksport danych do CSV/Excela

Opcjonalnie, ale przydatne:

pip install fake-useragent  # Uwaga: repo zarchiwizowane w kwietniu 2026, ale nadal możliwe do instalacji

Krok po kroku: jak scrapować Yelp w Pythonie

To jest główny tutorial. Kluczowa zasada, która sprawia, że wszystko jest znacznie bardziej odporne na zmiany: omijaj selektory CSS i pobieraj ukryty JSON. Yelp losowo zmienia nazwy klas CSS przy buildzie (y-css-14xwok2 w jednym tygodniu, y-css-hcq7b9 w następnym), więc każdy scraper oparty na tych klasach psuje się w ciągu kilku tygodni. Osadzone payloady JSON — application/ld+json i react-root-props — są stabilne.

Krok 2: Scrapowanie wyników wyszukiwania Yelp

Adresy wyszukiwania Yelp mają przewidywalny format: https://www.yelp.com/search?find_desc={term}&find_loc={location}. Dane z wyników są osadzone w tagu <script data-id="react-root-props"> jako JSON — a nie w bałaganie klas CSS.

import re, json, jmespath
from curl_cffi import requests
from parsel import Selector

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,"
              "image/avif,image/webp,image/apng,*/*;q=0.8",
    "accept-language": "en-US,en;q=0.9",
    "accept-encoding": "gzip, deflate, br",
    "cookie": "intl_splash=false",
}

def scrape_search(term: str, location: str, max_pages: int = 3):
    results = []
    for page in range(max_pages):
        url = (f"https://www.yelp.com/search?"
               f"find_desc={term}&find_loc={location}&start={page * 10}")
        r = requests.get(url, headers=HEADERS, impersonate="chrome131")
        if r.status_code != 200:
            print(f"Blocked on page {page}: {r.status_code}")
            break
        sel = Selector(text=r.text)
        script = sel.xpath(
            "//script[@data-id='react-root-props']/text()"
        ).get() or ""
        m = re.search(r"react_root_props\s*=\s*(\{.*?\});", script, re.S)
        if not m:
            print(f"No react-root-props found on page {page} — possible soft block")
            break
        data = json.loads(m.group(1))
        businesses = jmespath.search(
            "legacyProps.searchAppProps.searchPageProps"
            ".mainContentComponentsListProps"
            "[?searchResultBusiness].searchResultBusiness.{"
            "name: name, url: businessUrl, rating: rating, "
            "reviews: reviewCount, phone: phone, "
            "neighborhoods: neighborhoods}",
            data,
        ) or []
        results.extend(businesses)
        import time, random
        time.sleep(random.uniform(3, 7))
    return results

Powinieneś dostać listę słowników z nazwami firm, URL-ami, ocenami i liczbą recenzji. Jeśli react-root-props nie ma w odpowiedzi, dostałeś „shell” blokady — zmień IP i spróbuj ponownie.

Nagłówek Cookie: intl_splash=false to standardowy workaround dla krajowego ekranu powitalnego Yelp. Bez niego IP spoza USA trafiają na stronę splash, która wygląda jak miękka blokada, ale nią nie jest.

Krok 3: Scrapowanie stron firm w Yelp

Każdy URL firmy z wyników wyszukiwania prowadzi do strony szczegółów z bogatszym zestawem danych. Najstabilniejszym celem ekstrakcji jest blok <script type="application/ld+json"> — zawiera uporządkowane dane schema.org, które Yelp utrzymuje dla SEO i nie zaciemnia.

def scrape_business(biz_url: str) -> dict:
    url = f"https://www.yelp.com{biz_url}" if biz_url.startswith("/") else biz_url
    r = requests.get(url, headers=HEADERS, impersonate="chrome131")
    if r.status_code != 200:
        return {"url": url, "error": r.status_code}
    sel = Selector(text=r.text)
    biz_id = sel.css('meta[name="yelp-biz-id"]::attr(content)').get()
    for raw in sel.css('script[type="application/ld+json"]::text').getall():
        try:
            data = json.loads(raw)
        except json.JSONDecodeError:
            continue
        for node in (data if isinstance(data, list) else [data]):
            if node.get("@type") in (
                "Restaurant", "LocalBusiness", "FoodEstablishment",
                "HealthAndBeautyBusiness", "HomeAndConstructionBusiness",
            ):
                return {
                    "biz_id": biz_id,
                    "name": node.get("name"),
                    "rating": (node.get("aggregateRating") or {}).get("ratingValue"),
                    "review_count": (node.get("aggregateRating") or {}).get("reviewCount"),
                    "address": node.get("address"),
                    "telephone": node.get("telephone"),
                    "price_range": node.get("priceRange"),
                    "hours": node.get("openingHours"),
                    "url": url,
                }
    return {"biz_id": biz_id, "url": url}

Wartość meta[name="yelp-biz-id"] to zakodowane ID firmy, którego będziesz potrzebować do endpointu z recenzjami. Pobierz je tutaj — użyjesz go w następnym kroku.

Krok 4: Scrapowanie recenzji Yelp z paginacją

To tutaj Fusion API przegrywa, a scrapowanie wygrywa. Wewnętrzny endpoint GraphQL Yelp zwraca pełny tekst recenzji, informacje o recenzencie, daty, oceny i liczbę głosów — wszystko to, co API ukrywa.

Endpoint to https://www.yelp.com/gql/batch, a dla operacji GetBusinessReviewFeed używa statycznego documentId. Paginacja działa przez cursor zakodowany w base64.

import base64

GQL_URL = "https://www.yelp.com/gql/batch"
DOC_ID = "ef51f33d1b0eccc958dddbf6cde15739c48b34637a00ebe316441031d4bf7681"

def fetch_reviews(enc_biz_id: str, num_pages: int = 5):
    all_reviews = []
    for page in range(num_pages):
        offset = page * 10
        cursor = base64.b64encode(
            json.dumps({"version": 1, "offset": offset}).encode()
        ).decode()
        payload = [{
            "operationName": "GetBusinessReviewFeed",
            "variables": {
                "encBizId": enc_biz_id,
                "reviewsPerPage": 10,
                "after": cursor,
                "sortBy": "DATE_DESC",
                "language": "en",
            },
            "extensions": {
                "operationType": "query",
                "documentId": DOC_ID,
            },
        }]
        r = requests.post(
            GQL_URL,
            json=payload,
            headers={
                **HEADERS,
                "content-type": "application/json",
                "x-apollo-operation-name": "GetBusinessReviewFeed",
                "apollographql-client-name": "yelp-main-frontend",
            },
            impersonate="chrome131",
        )
        if r.status_code != 200:
            print(f"Review fetch failed at offset {offset}: {r.status_code}")
            break
        data = r.json()
        # Navigate the response structure to extract reviews
        try:
            reviews = data[0]["data"]["business"]["reviews"]["edges"]
            for edge in reviews:
                node = edge.get("node", {})
                all_reviews.append({
                    "reviewer": node.get("author", {}).get("displayName"),
                    "rating": node.get("rating"),
                    "date": node.get("localizedDate"),
                    "text": node.get("text", {}).get("full"),
                })
        except (KeyError, IndexError, TypeError):
            break
        import time, random
        time.sleep(random.uniform(3, 7))
    return all_reviews

Każda strona zwraca 10 recenzji. Zwiększaj offset w cursorze base64, aby przechodzić dalej. Parametr sortBy przyjmuje DATE_DESC (najnowsze najpierw), RATING_ASC, RATING_DESC i inne.

Krok 5: Eksport danych z Yelp

import pandas as pd

# Zakładając, że zebrałeś firmy i recenzje
df_businesses = pd.DataFrame(businesses)
df_businesses.to_csv("yelp_businesses.csv", index=False)

df_reviews = pd.DataFrame(all_reviews)
df_reviews.to_csv("yelp_reviews.csv", index=False)

# Albo zapisz jako JSON dla większej elastyczności
import json
with open("yelp_data.json", "w") as f:
    json.dump({"businesses": businesses, "reviews": all_reviews}, f, indent=2)

Dla osób wybierających no-code Thunderbit eksportuje te same dane bezpośrednio do Excel, Google Sheets, Airtable lub Notion — bez pandas i bez kodu do zapisu plików.

Playbook antyblokowy: jak scrapować Yelp bez blokad

To jest najważniejsza część artykułu. Zabezpieczenia antybotowe Yelp stały się znacznie ostrzejsze od końca 2024 roku — TLS fingerprinting, sprawdzanie reputacji IP, CAPTCHA i analiza zachowania są dziś standardem. Większość istniejących poradników jest już nieaktualna, bo powstała przed tą ofensywą.

yelp_antiblock_518f0447bb.png

Strategia musi być wielowarstwowa. Każda warstwa zmniejsza współczynnik blokad; razem pozwalają na długotrwałe scrapowanie.

Warstwa 1: realistyczne nagłówki żądań

Domyślne nagłówki requests w Pythonie wysyłają User-Agent: python-requests/2.x — blokada następuje natychmiast. Ale sam realistyczny User-Agent nie wystarczy. Yelp sprawdza cały zestaw nagłówków Client Hints pod kątem spójności.

FULL_HEADERS = {
    "authority": "www.yelp.com",
    "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,"
              "image/avif,image/webp,image/apng,*/*;q=0.8",
    "accept-language": "en-US,en;q=0.9",
    "accept-encoding": "gzip, deflate, br",
    "sec-ch-ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
    "sec-fetch-dest": "document",
    "sec-fetch-mode": "navigate",
    "sec-fetch-site": "same-origin",
    "sec-fetch-user": "?1",
    "upgrade-insecure-requests": "1",
    "referer": "https://www.yelp.com/",
    "cookie": "intl_splash=false",
}

Trzy błędy, które mogą Cię oznaczyć jako bota:

  1. UA twierdzi, że to Chrome, ale sec-ch-ua nie istnieje albo kłóci się z wersją UA
  2. sec-ch-ua-platform mówi „Windows”, a string UA wskazuje macOS
  3. Identyczny UA przy tysiącach żądań z jednego IP — rotuj pulę 10–20 aktualnych stringów Chrome/Firefox/Safari

Warstwa 2: limitowanie tempa i losowe opóźnienia

Przewidywalne wzorce czasowe są sygnałem ostrzegawczym. Dodaj losowe pauzy i wdroż exponential backoff przy błędach.

import random, time

def polite_get(client_get, url, attempt=0):
    r = client_get(url, headers=FULL_HEADERS, impersonate="chrome131")
    if r.status_code in (403, 429, 503):
        if attempt >= 4:
            raise RuntimeError(f"Blocked after {attempt + 1} attempts on {url}")
        backoff = 2 ** (attempt + 1) + random.random()
        print(f"  Got {r.status_code}, backing off {backoff:.1f}s (attempt {attempt + 1})")
        time.sleep(backoff)
        return polite_get(client_get, url, attempt + 1)
    time.sleep(random.uniform(3, 7))
    return r
ParametrZalecana wartość
Losowa przerwa między żądaniamirandom.uniform(3, 7) sekund
Backoff przy 429/403/5032 → 4 → 8 → 16 s, maks. 5 prób
Jednoczesne workery na jedno IP1 (serializuj per IP; do równoległości używaj proxy)
Maks. stabilny poziom dla residential IPok. 1 żądanie / 5 s (~12 rpm)

Warstwa 3: rotacja User-Agentów i sesji

Rotuj pulę prawdziwych stringów User-Agent przeglądarek. Zachowuj sesje i ciasteczka, aby naśladować naturalne przeglądanie — Yelp używa detekcji opartej na cookies, więc tworzenie nowej sesji dla każdego żądania też wygląda podejrzanie.

UA_POOL = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/537.36 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",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14.4; rv:125.0) Gecko/20100101 Firefox/125.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 Safari/17.4.1",
    # Dodaj 5–10 kolejnych aktualnych stringów
]

Warstwa 4: rotacja proxy

Przy realnej skali potrzebujesz residential proxy. Datacenter i darmowe proxy nie działają na Yelp — warstwa reputacji IP prewencyjnie blokuje zakresy AWS, GCP i DigitalOcean.

DostawcaCena startowa $/GBUwagi
IPRoyal$1.75/GBNajtańszy; prowadzi najczęściej cytowany poradnik o Yelp
Decodo (dawniej Smartproxy)$3.20–$3.50Najlepszy stosunek GB/cena przy większej skali
Bright Data$4.00 (PAYG)Pula 150M+ IP; osobna strona Yelp Proxies
Oxylabs$6.00–$8.00Premium; 10M+ IPs
Aluvia (mobile SIM)$3.00Prawdziwe mobilne IP amerykańskich operatorów, ukierunkowane na Yelp

Rotujące residential IP (nowy adres przy każdym żądaniu) sprawdzają się najlepiej przy wysokiej liczbie zapytań do wyszukiwania. Sticky sessions (jedno IP przez 10 minut) są lepsze, gdy chcesz utrzymać cookies w przepływie strona firmy → recenzje → paginacja.

Warstwa 5: wykrywanie blokad i reagowanie na nie

Nie każda blokada wygląda tak samo. Yelp często serwuje ogólny shell „page not available” zamiast CAPTCHA, przez co naiwne scrapery myślą, że dostały dane, podczas gdy w rzeczywistości otrzymały pustą odpowiedź.

BLOCK_MARKERS = (
    "captcha", "px-captcha", "page not available",
    "access denied", "unusual traffic",
)

def is_blocked(resp):
    if resp.status_code in (401, 403, 429, 503):
        return True
    body = resp.text.lower()
    if any(m in body for m in BLOCK_MARKERS):
        return True
    # Jeśli to strona wyszukiwania/firmy, ale nie ma react-root-props,
    # Yelp wysłał okrojoną odpowiedź blokującą
    if "react-root-props" not in body and "/biz/" in str(resp.url):
        return True
    return False
SygnałZnaczenie
HTTP 403Twarda blokada — IP/nagłówki/TLS spalony
HTTP 429Limit tempa — często do odzyskania dzięki backoff
HTTP 503Ogólna blokada albo przeciążenie
Przekierowanie do /error lub treść „page not available”Miękka blokada
Pusty z samymi Strona challenge, czeka na JS
captcha / g-recaptcha / px-captcha w treściEskalacja — wymagana CAPTCHA
Brak react-root-props na stronie listinguOkrojona odpowiedź blokująca

Warstwa 6: odporny trik parsowania — ukryty JSON zamiast selektorów CSS

Warto powtórzyć: Yelp losuje nazwy klas CSS przy buildzie. Scraper przypięty do h3.y-css-14xwok2 przestanie działać w ciągu kilku tygodni, gdy Yelp wdroży h3.y-css-hcq7b9.

Payloady, które nie zmieniają się tak łatwo:

  • <script type="application/ld+json"> — dane schema.org (nazwa, adres, telefon, ocena, godziny)
  • <script data-id="react-root-props"> — pełne dane wyników wyszukiwania jako JSON
  • https://www.yelp.com/gql/batch — endpoint GraphQL z recenzjami i stabilnym documentId

Jeśli parsujesz klasy CSS, budujesz na piasku. Parsuj JSON.

Warstwa 7: awaryjny tryb stealth browser

Przechodź do headless browsera tylko wtedy, gdy curl_cffi + residential proxies nie wystarczają — zwykle gdy Yelp pokazuje stronę challenge JS albo CAPTCHA.

Dla 95% scrapowania firm, wyników i recenzji curl_cffi + ukryty JSON + residential proxies jest szybsze, tańsze i bardziej niezawodne niż przeglądarka. Ale jeśli już potrzebujesz browsera:

NarzędzieStatus (2025)Uwagi
rebrowser-playwrightPolecany punkt startowyZmieniony Playwright z poprawkami pod wycieki CDP
nodriverNajlepszy stealth dla ChromeNastępca undetected-chromedriver; omija protokół WebDriver
patchrightAktywnie rozwijany fork PlaywrightPrzechodzi nowoczesne testy detekcji
playwright-stealthDojrzałyŁata navigator.webdriver, usuwa HeadlessChrome z UA

Na Yelp pomiń zwykłe Selenium. Jest zbyt łatwe do fingerprintingu.

Yelp Fusion API vs scrapowanie w Pythonie vs Thunderbit: pełne porównanie

WymiarYelp Fusion APIScrapowanie w PythonieThunderbit
Pełny tekst recenzji❌ 3 fragmenty × ~160 znaków✅ Bez limitu (GraphQL)✅ Wbudowany szablon recenzji
Metadane recenzji (głosy, odpowiedzi właściciela)✅ przez pola sugerowane przez AI
Zdjęcia❌ (0 w planie Base)✅ Bez limitu
Maks. wyników na wyszukiwanie240 (wcześniej 1 000 przed 2024)Bez limitu (z paginacją)Bez limitu
Dzienny limit300–500 (nowi) / 5 000 (legacy)Tylko budżet na proxyOparte na kredytach (3 000/mies. w Pro)
Czas konfiguracji~15 minOd kilku godzin do kilku dni~2 minuty
Obsługa antybotaN/DTwój problemObsługiwane (tryb Cloud)
Ryzyko prawneNiskie (oficjalne)Średnie (szara strefa ToS)Średnie (tak samo jak scrapowanie)
Koszt startowy$29/mies.ok. $0.75–$4/GB proxy + czas devDarmowy plan
Koszt przy dużym użyciu$643+/mies.$50–$500/mies. proxy + czas dev$38–$49/mies.
Eksport danychJSONCSV/JSON (musisz napisać)Excel / Sheets / Airtable / Notion — za darmo
UtrzymanieNiskieWysokie (selektory się psują, antybot się zaostrza)Niskie (AI dostosowuje się ponownie)

Wskazówki prawne i etyczne dotyczące scrapowania Yelp

Nie jestem prawnikiem i to nie jest porada prawna. Ale krajobraz prawny zmienił się na tyle w ciągu ostatnich dwóch lat, że warto znać podstawy, zanim zainwestujesz czas w projekt scrapowania Yelp.

Co mówi regulamin Yelp: Aktualizacja ToS z października 2025 wprost zabrania używania „jakiegokolwiek robota, pająka... lub innego zautomatyzowanego narzędzia” do „uzyskiwania dostępu, pobierania, kopiowania, scrapowania lub indeksowania jakiejkolwiek części Usługi”. Dodano też zapis o „AI Technologies i/lub innych zautomatyzowanych narzędziach”.

Wsparcie Yelp potwierdza: „Yelp nie zezwala na żadne scrapowanie strony.”

Co mówi robots.txt: Plik robots.txt ma wildcard User-agent: * / Disallow: / i dodatkowo blokuje GPTBot, ClaudeBot, PerplexityBot, CCBot oraz Meta-ExternalAgent. Białą listę mają tylko Googlebot, Bingbot i kilka crawlerów społecznościowych.

Istotny precedens prawny: W sprawie Meta v. Bright Data (N.D. Cal. styczeń 2024) sąd orzekł, że scrapowanie publicznie dostępnych danych bez logowania nie naruszało ToS Meta. Kluczowe rozróżnienie to: publiczne dane bez logowania vs. dane za logowaniem. Sprawa hiQ v. LinkedIn pokazała, że scrapowanie publicznych danych prawdopodobnie nie narusza CFAA, ale hiQ przegrało nadal na roszczeniach stanowych (trespass to chattels, misappropriation) i dostało wyrok na $500 000.

Praktyczne zasady:

  • Scrapuj wyłącznie publicznie dostępne strony bez logowania
  • Ograniczaj tempo żądań (opóźnienia w tym poradniku pełnią też funkcję etycznego rate limitu)
  • Nie odsprzedawaj surowego tekstu recenzji przypisanego do konkretnych użytkowników — szanuj prywatność recenzentów
  • Przestrzegaj lokalnych przepisów o ochronie danych (CCPA, GDPR)
  • Nie loguj się, żeby scrapować — to przekracza granicę autoryzacji
  • Traktuj informacje o firmie (nazwa/adres/telefon/ocena) jako publiczne dane faktyczne; tekst recenzji traktuj jako bardziej wrażliwy

W swojej konkretnej sytuacji skonsultuj się z prawnikiem.

Podsumowanie

Trzy ścieżki, jeden cel.

Yelp Fusion API to opcja oficjalna i mało wymagająca w utrzymaniu — ale ogranicza się do 3 fragmentów recenzji i zaczyna się od $29/miesiąc. Scrapowanie w Pythonie daje pełną kontrolę nad każdym punktem danych w Yelp, ale wymaga realnej inwestycji: curl_cffi do imitacji TLS, residential proxies, losowych opóźnień, parsowania ukrytego JSON-a i stałego utrzymania wraz z rozwojem zabezpieczeń Yelp. Thunderbit pozwala przejść od „potrzebuję danych z Yelp” do „oto mój arkusz” w około 30 sekund, bez kodu i bez konfiguracji proxy.

Elementy antyblokowe, które naprawdę działają w 2025 roku: realistyczne nagłówki z pełnym Client Hints, curl_cffi do imitacji fingerprintu TLS, losowe opóźnienia z exponential backoff, rotacja residential proxy oraz — co najważniejsze — parsowanie ukrytego JSON-a (application/ld+json i react-root-props) zamiast kruchych selektorów CSS.

Nie wiesz, która ścieżka będzie najlepsza? Najpierw wypróbuj darmowy plan Thunderbit. Jeśli wystarczy, oszczędzasz sobie godzin pracy. Jeśli potrzebujesz większej kontroli — pełnych pipeline’ów programistycznych, własnych pól, ścisłej integracji z CRM — powyższy przewodnik po Pythonie Cię prowadzi. A jeśli chcesz szerzej spojrzeć na krajobraz narzędzi do scrapowania, sprawdź nasze zestawienie najlepszych rozszerzeń Chrome do web scrapingu albo przewodnik jak pobrać dane ze strony do Excela.

Wypróbuj Thunderbit do ekstrakcji danych z Yelp Get Started Free

FAQ

Czy mogę scrapować Yelp za darmo w Pythonie?

Tak — używając darmowych bibliotek, takich jak curl_cffi, parsel i jmespath. Ale przy jakiejkolwiek realnej skali (więcej niż kilka dziesiątek stron) będziesz potrzebować płatnych residential proxy, które zaczynają się od około $1.75/GB w IPRoyal. Thunderbit oferuje też darmowy plan z 6 stronami miesięcznie dla szybkiej ekstrakcji no-code.

Czy Yelp blokuje scrapery?

Tak, i to agresywnie. Yelp stosuje TLS/JA3 fingerprinting, scoring reputacji IP, CAPTCHA, analizę zachowania oraz rotujące, zaciemnione klasy CSS. Zwykłe requests jest blokowane przy pierwszym żądaniu. Warstwowa strategia antyblokowa z tego przewodnika — curl_cffi do imitacji TLS, realistyczne nagłówki, losowe opóźnienia i residential proxies — to rozwiązanie działające w 2025 roku.

Czy Yelp Fusion API jest lepsze niż scrapowanie?

To zależy od potrzeb. API jest oficjalne i niskiego ryzyka, ale zwraca tylko 3 fragmenty recenzji po ok. 160 znaków każdy, ogranicza wyniki wyszukiwania do 240 i startuje od $29/miesiąc. Jeśli potrzebujesz pełnego tekstu recenzji, metadanych recenzji albo więcej niż kilkuset rekordów dziennie, scrapowanie to jedyna opcja.

Jak scrapować recenzje Yelp w Pythonie?

Użyj curl_cffi z impersonate="chrome131", aby pobrać stronę firmy, wyciągnij zakodowane ID firmy z <meta name="yelp-biz-id">, a następnie wyślij POST do https://www.yelp.com/gql/batch z operacją GetBusinessReviewFeed i przechodź przez wyniki za pomocą base64-owanego kursora after. Kod krok po kroku znajdziesz w sekcji tutoriala powyżej. Repozytorium Scrapfly Yelp scraper repo to również solidny punkt odniesienia.

Czy mogę scrapować Yelp bez kodowania?

Tak — AI Web Scraper Thunderbit ma gotowe szablony Yelp business i reviews. Otwórz stronę Yelp, kliknij AI Suggest Fields, kliknij Scrape. Eksport do Google Sheets, Excel, Airtable i Notion jest darmowy na każdym planie, także bezpłatnym.

Dowiedz się więcej

Shuai Guan
Shuai Guan
CEO w Thunderbit | Ekspert ds. automatyzacji danych AI Shuai Guan jest CEO Thunderbit oraz absolwentem wydziału inżynierii University of Michigan. Czerpiąc z niemal dekady doświadczenia w branży technologicznej i architekturze SaaS, specjalizuje się w przekuwaniu złożonych modeli AI w praktyczne, niewymagające kodowania narzędzia do استخراج danych. Na tym blogu dzieli się szczerymi, sprawdzonymi w boju spostrzeżeniami na temat web scrapingu i strategii automatyzacji, które pomogą Ci tworzyć mądrzejsze, oparte na danych procesy pracy. Gdy nie optymalizuje przepływów danych, z tą samą dbałością o szczegóły oddaje się swojej pasji do fotografii.
Spis treści

Zbierz dane ze strony, po prostu o to prosząc

Powiedz, czego potrzebujesz, prostym angielskim. A najlepiej: nie mów nic.

Wypróbuj Thunderbit darmowe
Wyodrębniaj dane dzięki AI
Łatwo przenoś dane do Google Sheets, Airtable lub Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week