Näin kaavin Yelp-dataa Pythonilla jäämättä kiinni

Viimeksi päivitetty April 15, 2026
Näin kaavin Yelp-dataa Pythonilla jäämättä kiinni

Yelpissä on yli 330 miljoonaa arvostelua 8,4 miljoonalla aktiivisella yrityssivulla — ja tämän datan saaminen käyttökelpoiseen muotoon on nyt vaikeampaa kuin koskaan. Yelpin vuosien 2024–2025 tiukennettu torjunta bottien käyttöä vastaan on rikkonut hiljaisesti suurimman osan olemassa olevista Python-kaavojen mukaisista kaavintaoppaista.

Jos olet viime aikoina yrittänyt ajaa Yelp-kaavintaohjelmaa ja törmännyt 403-virheisiin, tyhjiin HTML-vastauksiin tai CAPTCHAsuojiin, joita ei ollut vielä puoli vuotta sitten, et kuvittele tätä. Yelp käyttää nyt TLS/JA3-fingerprintingia, kiertäviä obfuskoituja CSS-luokkanimiä ja aggressiivista IP-maineen pisteytystä — eli vanha requests + BeautifulSoup -lähestymistapa, jota jokainen opas yhä suosittelee, kaatuu jo ensimmäiseen pyyntöön. Olen käyttänyt viikkoja testaten eri tapoja Yelpin nykyistä pinottua suojausta vastaan, ja tämä opas kattaa kaiken, mikä oikeasti toimii vuonna 2025: virallisen Fusion API:n (ja miksi se ei todennäköisesti riitä), täyden Python-kaavintatyönkulun kerroksellisella estojen kiertostrategialla sekä kahden klikkauksen koodittoman vaihtoehdon Thunderbitillä niille, jotka haluavat vain datan ilman pitkää debuggausrumbaa.

Kokeile Thunderbitiä Yelp-kaavintaan

Miksi kaapia Yelp-dataa Pythonilla — ja kuka siitä oikeasti hyötyy?

Ennen kuin kirjoitat riviäkään koodia, mikä on Yelp-datan todellinen liiketoimintahyöty? Alusta ei ole vain ravintola-arvostelusivusto — se on käytännössä reaaliaikainen tietokanta paikallisista yrityksistä, jossa on jäsennellyt yhteystiedot, arvosanat, kategoriat, aukioloajat ja satoja miljoonia asiakasarvosteluja.

yelp_stats_bd6a43108e.png

Näin eri käyttäjät hyötyvät ja mitä he yleensä poimivat:

KäyttötapausKeskeiset kentätMiksi sillä on väliä
Myynti ja liidien generointiYrityksen nimi, puhelin, verkkosivusto, osoite, kategoria, arvosanaRakenna kohdennettuja potentiaalisten asiakkaiden listoja paikallisista pienyrityksistä — 4/5 Yelp-käyttäjää on ostopäätösvalmis heti palveluun tullessaan
Kilpailija-analyysiArvostelut, tähtiarvostelut, arvostelujen määrä, sävySeuraa kilpailijoiden mainetta, tunnista palveluaukot ja havaitse trendit
Markkinatutkimus ja NLPKoko arvosteluteksti, päivämäärät, arvostelijan metatiedotSentimenttianalyysi, aiheiden mallinnus — Yelp-arvostelut ovat akateemisessa tutkimuksessa yksi käytetyimmistä NLP-aineistoista
Kiinteistöt ja sijaintivalintaYritystiheys, kategoriajakauma, alueen arvostelulaatuKetjujen ja vähittäiskaupan sijaintivalinta — Yelp myy Location Intelligence -ratkaisua lisensoituna B2B-tuotteena juuri tätä varten
Verkkokauppa ja operatiivinen toimintaHinnoittelusignaalit, asiakasvalitukset, palveluajatSeuraa, miten kilpailijoita arvioidaan, ja tunnista toimintamalleja

Yhteinen nimittäjä: todellinen tavoite on jäsennelty data, ja Python on vain yksi väline sen saamiseen. Osa lukijoista haluaa täyden ohjelmallisen hallinnan. Toiset tarvitsevat vain taulukon Austinin putkimieskontakteista. Molemmat polut käydään läpi tässä oppaassa.

Yelp Fusion API vai Python-kaavinta: kumpaa kannattaa käyttää?

Useimmat oppaat ohittavat tämän päätöksen täysin ja hyppäävät suoraan koodiin arvioimatta, olisiko virallinen Yelp Fusion API (nykyisin brändätty nimellä “Yelp Places API”) riittänyt. Oman kokemukseni mukaan tämän arvioinnin tekeminen säästää tuntikausia turhaa työtä — API on erinomainen joihinkin tarpeisiin, mutta täysin riittämätön toisiin.

Mitä Fusion API oikeasti tarjoaa

Fusion API tarjoaa jäsennellyn yrityshaun, yritystiedot, automaattitäydennyksen ja arvostelupisteen. Se on valtuutettu, hyvin dokumentoitu eikä vaadi anti-bot-kikkailua.

Mutta arvostelupäätepisteessä homma menee pieleen. Yelpin työntekijät ovat vahvistaneet GitHubissa seuraavaa:

“Yelp API ei palauta koko arvostelutekstiä. Oletuksena tarjotaan kolme 160 merkin mittaista arvostelukatkelmaa.” — Yelp staff -vastaus, GitHub Issue #163

Tämä ei ole bugi — se on tarkoituksellista. API rajoittaa fyysisesti 3 arvostelukatkelmaan (Premiumissa 7), ja jokainen on typistetty noin 160 merkkiin. Ei arvostelun metatietoja (hyödyllinen/hauska/cool), ei arvostelijan historiaa, ei omistajan vastauksia. Ja uusien asiakkaiden päivittäinen rajoitus putosi toukokuun 2023 jälkeen 300–500 kutsuun päivässä — aiemmasta 5 000:sta. Aloitushinta on $29/kk.

Päätöspuikko

TekijäYelp Fusion APIPython-kaavintaThunderbit (kooditon)
Koko arvosteluhistoria❌ Vain 3 katkelmaa (~160 merkkiä/kpl)✅ Kaikki arvostelut GraphQL:n kautta✅ Kaikki näkyvät arvostelut
Rajoitukset300–500/pv (uudet); 5 000 (vanhat)Itse hallittu (proxy-budjetti)Kreditipohjainen
Käyttöönotto~15 min (API-avain + SDK)Tunteja tai päiviä~2 min
Yrityskentät~20 jäsenneltyä kenttääRajoittamaton (HTML/JSON-parsinta)AI:n ehdottamat kentät
Anti-bot-käsittelyEi sovellu (valtuutettu)Rakennettava itseHoituu automaattisesti
Juridinen riski✅ Valtuutettu⚠️ ToS-harmaa alue⚠️ Sama kuin kaavinnassa
HintaAlkaen $29/kkIlmainen (+ proxy-kulut $0,75–$4/GB)Ilmainen taso saatavilla
YlläpitoMatala (API vakaa)Korkea (valitsimet vanhenevat, suojaus kiristyy)Matala (AI mukautuu uudelleen)

Käytä Fusion API:a, jos: tarvitset perustiedot yrityksistä, pieniä hakuja tai valtuutetun integraation — ja 3 arvostelukatkelmaa per yritys riittää.

Käytä Python-kaavintaa, jos: tarvitset täyden arvostelutekstin, kaikki arvostelut yhdestä yrityksestä, arvostelujen metatiedot, yli 240 tulosta haussa tai budjettisi on alle $29/kk.

Käytä Thunderbitiä, jos: haluat datan nopeasti ilman koodin kirjoittamista tai ylläpitoa. Tästä lisää alla koodittomassa osiossa.

Kooditon oikotie: kaavi Yelp Thunderbitillä (ei Pythonia)

Ennen kuin syvennymme Pythoniin, tässä nopein reitti niille, joiden oikea tavoite on data — ei ohjelmointi. Jokainen kilpailijan opas olettaa Python-osaamista, mutta Thunderbitillä tehdyn työni aikana olen huomannut, että valtava osa “scrape Yelp” -hakijoista on myyjiä, operatiivisia johtajia ja pienyrittäjiä, jotka haluavat vain taulukon paikallisista yrityksistä — eivät tiivistä kurssia TLS-fingerprintingiin.

Thunderbitillä on valmiina Yelp-pohjia:

  • Yelp Business Web Scraper — poimii yrityksen nimen, arvosanan, yhteystiedot, osoitteen, aukioloajat ja kategorian
  • Yelp Review Scraper — poimii arvostelijan käyttäjänimen, arvostelun sisällön, arvosanan, päivämäärän ja sijainnin

Miten se toimii käytännössä

  1. Avaa Yelp-hakutulossivu tai yrityssivu Chromessa
  2. Klikkaa AI Suggest Fields Thunderbit-laajennuksessa — AI lukee sivun ja ehdottaa sarakkeet (yrityksen nimi, arvosana, arvostelujen määrä, hintataso, kategoria, osoite, puhelin, URL)
  3. Klikkaa Scrape — valmis

Valmiilla Yelp-pohjilla se on vielä helpompaa: avaa malli ja klikkaa Scrape.

Alasivujen kaavinta hoitaa rikastuksen automaattisesti — aloita Yelp-hakutulossivulta, ota käyttöön alasivukaavinta, ja Thunderbit käy jokaisella yrityssivulla poimimassa aukioloajat, koko arvostelut, verkkosivun, kuvat ja palvelut. Ei lisäasetuksia.

Sivutus on automaattinen — sekä klikkaus- että vierityspohjainen sivutus toimii suoraan valmiina. (Jos haluat tietää enemmän, katso sivutusoppaamme.)

Vienti on ilmainen kaikilla tasoilla — Excel, Google Sheets, Airtable, Notion, CSV, JSON. Ei pandasia, ei CSV-kirjoituskoodia.

Aikavertailu

AikaPython-kaavinThunderbit
Ensimmäinen ajoTunteja tai päiviä (valitsimet, sivutus, proxyt, retry-logiikka)~30 sekuntia valmiilla Yelp-pohjalla
Kun Yelp muuttaa merkkaustaKirjoita valitsimet uusiksi käsinKlikkaa AI Suggest Fields uudelleen — mukautuu automaattisesti
Kun IP estetäänDebuggaa, kierrätä proxy-poolit, testaa uudelleenCloud-tila hoitaa IP-kierron
Vie Google SheetiinKirjoita OAuth- ja pandas-liimaYksi klikkaus, ilmainen

Jos kokeilet ensin Thunderbitiä ja huomaat sen riittävän tarpeisiisi, voit ohittaa loppuartikkelin. Jos tarvitset täyden ohjelmallisen hallinnan, omat kentät tai skaalaa yli muutaman tuhannen tietueen kuukaudessa — jatka lukemista.

Python-kirjastot Yelp-kaavintaan: minkä valitsen?

“Pitäisikö käyttää Scrapyä, BS4+requestsia vai Seleniumia?” on yksi yleisimmistä kysymyksistä r/webscraping-keskusteluissa Yelpistä. Silti jokainen opas valitsee vain oman suosikkikirjastonsa eikä selitä miksi. Tässä rehellinen yhteenveto.

Vuoden 2025 todellisuus: requests + BeautifulSoup on rikki Yelpissä

Se pino, jota jokainen klassinen Yelp-opas suosittelee — pip install requests beautifulsoup4jää kiinni jo ensimmäisessä pyynnössä vuonna 2025. Ei 50. pyynnössä. Ensimmäisessä.

Syy: Pythonin requests-kirjasto lähettää TLS/JA3-fingerprintin, joka ei vastaa mitään oikeaa selainta. Yelpin anti-bot-kerros tunnistaa sen TLS-kättelytasolla, ennen kuin User-Agent-otsikkoa edes luetaan. Testasin tätä toistuvasti — uusi IP, uskottavat otsikot, satunnaiset viiveet — ja silti sain välittömästi 403 Forbiddenin puhtaalla requestsillä.

Kirjastopäätösmatriisi

KirjastoParas käyttötarkoitusKäsittelee JS:n?Anti-Bot?OppimiskäyräNopeus
requests + BeautifulSoupYksinkertainen yhden sivun kaavinta (rikki Yelpissä)Erittäin matalaNopea (kunnes estetään)
httpx async + parselSuuren mittakaavan async-kaavintaMatalaErittäin nopea
curl_cffi + parselYelp-kohtainen: TLS-imitointi✅ TLS/JA3/HTTP2MatalaErittäin nopea
Scrapy 2.14Täydet crawl-putket sivutuksineenOsittain (scrapy-playwrightin kautta)AutoThrottle, retry-middlewareKeskitaso–korkeaNopea
Selenium 4.43 / Playwright 1.58JS-raskaat sivut, CAPTCHA-kiertotavatOsittainKeskitasoHidas (~10–30 sivua/min)
ThunderbitEi-ohjelmoijille, nopeaan poimintaan✅ (selaimessa)Sisäänrakennettu (Cloud-tila)Erittäin matalaNopea

curl_cffi-läpimurto

Kirjasto, joka muutti Yelp-kaavintatyöni, on curl_cffi — Python-sidonta curl-impersonatelle. Se lähettää täsmälleen saman TLS/JA3- ja HTTP/2-fingerprintin kuin oikea Chrome, ja sen API on suora korvaaja requestsille:

from curl_cffi import requests

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

Tämä yksi muutos — from curl_cffi import requests sekä impersonate="chrome131" — ohittaa Yelpin suurimman anti-bot-kerroksen ilman selaimen käynnistämistä. Omat testini osoittavat, että ero on välittömien 403-virheiden ja siistien 200-vastausten välillä.

Suositeltu pino Yelpille vuonna 2025: curl_cffi + parsel + jmespath + residential-proxyt. Jos tarvitset täyden crawl-putken ajastuksella, kääri se Scrapy 2.14:ään ja curl_cffi-pohjaiseen downloader-middlewareen.

Python-ympäristön pystyttäminen Yelpin kaavintaa varten

  • Vaikeustaso: Keskitaso
  • Tarvittava aika: ~15 min asennukseen, 1–2 h toimivaan kaavintaohjelmaan
  • Mitä tarvitset: Python 3.10+ (3.12 suositeltu), terminaali ja halutessasi residential-proxy-palvelu

Vaihe 1: Luo virtuaaliympäristö ja asenna paketit

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

Mitä kukin paketti tekee:

  • curl_cffi — tekee HTTP-pyynnöt Chromen TLS-fingerprintillä (anti-bot-kierto)
  • parsel — CSS/XPath-valitsimet HTML:n parsimiseen (sama moottori kuin Scrapyssa, kevyempi)
  • jmespath — deklaratiivinen JSON-kysely (siistimpi kuin sisäkkäinen dict-työskentely Yelpin upotetun JSONin kanssa)
  • pandas — datan vienti CSV/Excel-muotoon

Valinnainen mutta hyödyllinen:

pip install fake-useragent  # Huom: repo arkistoitiin huhtikuussa 2026, mutta on yhä asennettavissa

Vaihe vaiheelta: miten kaapia Yelp-dataa Pythonilla

Tämä on varsinainen opetusosa. Keskeinen oivallus, joka tekee kaikesta paljon kestävämpää: ohita CSS-valitsimet ja poimi piilotettu JSON. Yelp satunnaistaa CSS-luokkanimet build-vaiheessa (y-css-14xwok2 yhtenä viikkona, y-css-hcq7b9 seuraavana), joten niihin sidottu kaavin hajoaa viikkojen sisällä. Upotetut JSON-payloadit — application/ld+json-schema ja react-root-props — ovat vakaita.

Vaihe 2: kaavi Yelp-hakutulokset

Yelp-haku-URL:t noudattavat ennustettavaa muotoa: https://www.yelp.com/search?find_desc={term}&find_loc={location}. Hakutulosten data on upotettu <script data-id="react-root-props"> -tagiin JSONina — ei CSS-luokkien sekaan renderöitynä.

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"Estetty sivulla {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"react-root-props ei löytynyt sivulta {page} — mahdollinen pehmeä esto")
            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

Saat takaisin listan sanakirjoja, joissa on yrityksen nimi, URL, arvosana ja arvostelumäärä. Jos react-root-props puuttuu vastauksesta, sinulle on tarjoiltu estokuori — vaihda IP ja yritä uudelleen.

Cookie: intl_splash=false on vakiokierto Yelpin maa-splash-uudelleenohjaukseen. Ilman sitä ei-yhdysvaltalaiset IP:t päätyvät splash-sivulle, joka näyttää pehmeältä estolta, mutta ei ole sitä.

Vaihe 3: kaavi Yelp-yrityssivut

Jokainen hakutulosten yritys-URL johtaa tarkempaan sivuun, jossa on rikkaampi data. Vakain poimintakohde on <script type="application/ld+json"> -lohko — se sisältää schema.org-rakennetta, jota Yelp ylläpitää SEO:ta varten eikä obfuskoi sitä.

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}

meta[name="yelp-biz-id"] -arvo on koodattu yritystunniste, jota tarvitset arvostelupäätepisteeseen. Ota se talteen tästä — käytät sitä seuraavassa vaiheessa.

Vaihe 4: kaavi Yelp-arvostelut sivutuksella

Tässä kohtaa Fusion API jää jälkeen ja kaavinta loistaa. Yelpin sisäinen GraphQL-eräpäätepiste palauttaa koko arvostelutekstin, arvostelijan tiedot, päivämäärät, arvosanat ja äänimäärät — kaiken sen, minkä API piilottaa.

Päätepiste on https://www.yelp.com/gql/batch, ja se käyttää staattista documentId-tunnusta GetBusinessReviewFeed-operaatiolle. Sivutus toimii base64-koodatun cursorin kautta.

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"Arvostelun haku epäonnistui offsetissa {offset}: {r.status_code}")
            break
        data = r.json()
        # Navigoi vastauksen rakenteessa ja poimi arvostelut
        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

Jokainen sivu palauttaa 10 arvostelua. Kasvata offset-arvoa base64-cursorissa sivuttaaksesi. sortBy-parametri hyväksyy DATE_DESC (uusimmat ensin), RATING_ASC, RATING_DESC ja muita.

Vaihe 5: vie kaavittu Yelp-data

import pandas as pd

# Oletetaan, että olet kerännyt yritykset ja arvostelut
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)

# Tai tallenna JSON-muodossa joustavuuden vuoksi
import json
with open("yelp_data.json", "w") as f:
    json.dump({"businesses": businesses, "reviews": all_reviews}, f, indent=2)

Koodittomalla polulla Thunderbit vie saman datan suoraan Exceliin, Google Sheetiin, Airtableen tai Notioniin — ilman pandasia tai tiedostonkirjoituskoodia.

Estojen kiertämisen pelikirja: miten kaapia Yelp ilman että jää kiinni

Tämä osio on koko artikkelin ydin. Yelpin anti-bot-keinot ovat selvästi koventuneet loppuvuodesta 2024 — TLS-fingerprinting, IP-maineen tarkistus, CAPTCHA:t ja käyttäytymisanalyysi ovat kaikki käytössä. Useimmat olemassa olevat oppaat ovat vanhentuneita, koska ne kirjoitettiin ennen tätä tiukennusta.

yelp_antiblock_518f0447bb.png

Strategia on kerroksittainen. Jokainen kerros pienentää estojen osuutta; yhdessä ne tekevät jatkuvasta kaavinnasta mahdollisen.

Kerros 1: uskottavat request-otsikot

Python requests lähettää oletuksena otsikon User-Agent: python-requests/2.x — se estetään välittömästi. Mutta edes uskottava User-Agent ei riitä. Yelp tarkistaa koko Client Hints -otsikkosarjan johdonmukaisuuden.

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",
}

Kolme virhettä, jotka laukaisevat hälytyksen:

  1. UA väittää olevansa Chrome, mutta sec-ch-ua puuttuu tai on ristiriidassa version kanssa
  2. sec-ch-ua-platform sanoo “Windows”, mutta UA-merkkijono viittaa macOS:ään
  3. Sama täsmälleen identtinen UA tuhansissa pyynnöissä yhdestä IP:stä — kierrätä 10–20 tuoreen Chrome/Firefox/Safari-merkkijonon poolia

Kerros 2: nopeusrajoitus ja satunnaiset viiveet

Ennustettavat aikamallit ovat punainen lippu. Lisää satunnaisia sleep-välejä ja toteuta eksponentiaalinen backoff virhevastausten kohdalla.

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"Estetty {attempt + 1} yrityksen jälkeen osoitteessa {url}")
        backoff = 2 ** (attempt + 1) + random.random()
        print(f"  Sait {r.status_code}-vastauksen, odotetaan {backoff:.1f}s (yritys {attempt + 1})")
        time.sleep(backoff)
        return polite_get(client_get, url, attempt + 1)
    time.sleep(random.uniform(3, 7))
    return r
ParametriSuositeltu arvo
Satunnainen tauko pyyntöjen välillärandom.uniform(3, 7) sekuntia
Backoff 429/403/503-virheissä2 → 4 → 8 → 16 s, enintään 5 yritystä
Samanaikaiset työntekijät per IP1 (serialisoi per IP; käytä proxya rinnakkaisuuteen)
Suurin kestävä tahti residential-IP:llänoin 1 pyyntö / 5 s (~12 rpm)

Kerros 3: User-Agentin ja session kierto

Kierrätä oikeiden selain-User-Agentien poolia. Säilytä sessiot ja evästeet, jotta käyttäytyminen näyttää aidolta — Yelp käyttää evästepohjaista tunnistusta, joten jokaisen pyynnön aloittaminen täysin uutena sessiona on itsessään epäilyttävää.

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",
    # Lisää 5–10 muuta tuoretta merkkijonoa
]

Kerros 4: proxy-kierto

Todellisessa volyymissa tarvitset residential-proxyt. Datacenter- ja ilmaisproxyt eivät toimi Yelpissä — Yelpin IP-mainekerros hylkää ennakoivasti AWS-, GCP- ja DigitalOcean-IP-alueet.

PalveluntarjoajaAlkuhinta $/GBHuomioita
IPRoyal$1.75/GBHalvin; ylläpitää usein siteerattua Yelp-opasta
Decodo (ent. Smartproxy)$3.20–$3.50Paras GB/$-suhde volyymissa
Bright Data$4.00 (PAYG)150M+ IP-pooli; oma Yelp Proxies -sivu
Oxylabs$6.00–$8.00Premium; 10M+ IP:tä
Aluvia (mobiili-SIM)$3.00Aidot US-carrier-mobiili-IP:t, asemoi itsensä Yelp-kaavintaan

Kierrättävät residential-proxyt (uusi IP jokaiselle pyynnölle) toimivat parhaiten suuren volyymin hakukroolauksessa. Sticky-sessionit (pidä sama IP 10 minuuttia) sopivat paremmin, kun evästeitä halutaan säilyttää yrityssivu → arvostelut → sivutus -polussa.

Kerros 5: estojen tunnistus ja käsittely

Kaikki estot eivät näytä samoilta. Yelp näyttää usein geneerisen “page not available” -kuoren CAPTCHAn sijaan, minkä vuoksi sinisilmäiset kaavimet luulevat saavansa dataa, vaikka oikeasti vastauksena on tyhjää.

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
    # Jos kyseessä on haku- tai yrityssivu, mutta react-root-props puuttuu,
    # Yelp on tarjonnut riisuttua estovastausta
    if "react-root-props" not in body and "/biz/" in str(resp.url):
        return True
    return False
SignaaliMerkitys
HTTP 403Kova esto — IP/otsikot/TLS poltettu
HTTP 429Nopeusrajoitus — usein palautettavissa backoffilla
HTTP 503Geneerinen esto tai kuormanhallinta
Uudelleenohjaus /error-polkuun tai “page not available” -sisältöPehmeä esto
Tyhjä , jossa vain Haastesivu odottaa JS:ää
captcha / g-recaptcha / px-captcha sisällössäTilanne eskaloitui — CAPTCHA vaaditaan
react-root-props puuttuu listaus­sivultaRiisuttu estovastaus

Kerros 6: kestävä parsintakikka — piilotettu JSON CSS-valitsimien sijaan

Toistetaan vielä: Yelp satunnaistaa CSS-luokkanimet build-vaiheessa. Kaavin, joka on sidottu h3.y-css-14xwok2:een, hajoaa viikkojen sisällä, kun Yelp julkaisee uudelleen h3.y-css-hcq7b9:n.

Payloadit, jotka eivät vaihdu:

  • <script type="application/ld+json"> — schema.org-jäsennelty data (nimi, osoite, puhelin, arvosana, aukioloajat)
  • <script data-id="react-root-props"> — koko hakutulosten JSON-data
  • https://www.yelp.com/gql/batch — GraphQL-arvostelupäätepiste vakaalla documentId:llä

Jos parsit CSS-luokkia, rakennat hiekalle. Parsii sen sijaan JSON.

Kerros 7: huomaamaton selainvararatkaisu

Siirry headless-selaimeen vain silloin, kun curl_cffi + residential-proxyt eivät pääse läpi — yleensä silloin, kun Yelp näyttää JavaScript-haastesivun tai CAPTCHAn.

95 prosentissa yritys-, haku- ja arvostelukaavinnasta curl_cffi + piilotettu JSON + residential-proxyt on nopeampi, halvempi ja luotettavampi kuin selain. Mutta jos selainta tarvitaan:

TyökaluTila (2025)Huomioita
rebrowser-playwrightSuositeltu aloituspisteDrop-in Playwright, jossa CDP-vuotot on paikattu
nodriverLuokkansa paras Chrome-huomaamattomuudessaundetected-chromedriverin seuraaja; välttää WebDriver-protokollan kokonaan
patchrightAktiivisesti ylläpidetty Playwright-haaraLäpäisee modernit tunnistustestit
playwright-stealthKypsäPaikkaa navigator.webdriver-arvon ja poistaa HeadlessChrome:n UA:sta

Ohita tavallinen Selenium Yelpissä. Se on liian helposti sormenjälkitunnistettava.

Yelp Fusion API vs. Python-kaavinta vs. Thunderbit: täydellinen vertailu

OminaisuusYelp Fusion APIPython-kaavintaThunderbit
Koko arvosteluteksti❌ 3 katkelmaa × ~160 merkkiä✅ Rajoittamaton (GraphQL)✅ Sisäänrakennettu arvostelupohja
Arvostelujen metatiedot (äänet, omistajan vastaukset)✅ AI:n ehdottamien kenttien kautta
Kuvat❌ (0 Base-tasolla)✅ Rajoittamaton
Maksimi tulokset haussa240 (ennen 2024:ää 1 000)Rajoittamaton (sivutettuna)Rajoittamaton
Päivittäinen rajoitus300–500 (uudet) / 5 000 (vanhat)Vain proxy-budjettiKreditipohjainen (3 000/kk Prossa)
Käyttöönotto~15 minTunteja tai päiviä~2 min
Anti-bot-käsittelyEi sovelluOngelmasiHoidettu (Cloud-tila)
Juridinen riskiMatala (valtuutettu)Keskitaso (ToS-harmaa alue)Keskitaso (sama kuin kaavinnassa)
Hinta (aloitus)$29/kk~$0.75–$4/GB proxyt + kehitysaikaIlmainen taso
Hinta (raskaassa käytössä)$643+/kk$50–$500/kk proxyt + kehitysaika$38–$49/kk
Datan vientiJSONCSV/JSON (sinun täytyy kirjoittaa se)Excel / Sheets / Airtable / Notion — ilmainen
YlläpitoMatalaKorkea (valitsimet vanhenevat, suojaus kiristyy)Matala (AI mukautuu uudelleen)

Lailliset ja eettiset vinkit Yelp-kaavintaan

En ole juristi, eikä tämä ole oikeudellista neuvontaa. Mutta oikeudellinen maisema on muuttunut sen verran kahden viime vuoden aikana, että perusteet kannattaa ymmärtää ennen kuin sijoitat aikaa Yelp-kaavintaprojektiin.

Mitä Yelpin käyttöehdot sanovat: Lokakuun 2025 käyttöehtopäivitys kieltää nimenomaisesti käyttämästä “mitään robottia, hämähäkkiä... tai muuta automatisoitua välinettä” palvelun minkä tahansa osan “käyttämiseen, hakemiseen, kopiointiin, kaapimiseen tai indeksointiin”. Mukaan tuli myös maininta “AI-teknologioista ja/tai muista automatisoiduista työkaluista”.

Yelp Support toistaa: “Yelp ei salli sivuston kaavintaa.”

Mitä robots.txt sanoo: Yelpin robots.txt sisältää wildcardin User-agent: * / Disallow: / ja estää erikseen GPTBotin, ClaudeBotin, PerplexityBotin, CCBotin ja Meta-ExternalAgentin. Vain Googlebot, Bingbot ja muutamat some-crawlerit on valkolistattu.

Merkittävä oikeustapaus: Meta v. Bright Data -tapauksessa (N.D. Cal. tammi 2024) oikeus katsoi, että julkisesti saatavilla olevan, uloskirjautuneen datan kaavinta ei rikkonut Metan käyttöehtoja. Keskeinen ero: uloskirjautunut julkinen data vs. kirjautunut data. hiQ v. LinkedIn -tapaus osoitti, että julkisen datan kaavinta ei todennäköisesti riko CFAA-lakia, mutta hiQ hävisi silti osavaltiotason vahingonkorvausväitteissä (trespass to chattels, misappropriation) ja sai 500 000 dollarin tuomion.

Käytännön ohjeet:

  • Kaavi vain julkisesti saatavilla olevia, uloskirjautuneita sivuja
  • Rajoita pyyntömääriäsi (tämän oppaan viiveet toimivat samalla eettisinä rate limitteinä)
  • Älä jälleenmyy raakaa arvostelutekstiä nimettyihin käyttäjiin liitettynä — kunnioita arvostelijoiden yksityisyyttä
  • Noudata paikallisia tietosuojalakeja (CCPA, GDPR)
  • Älä kirjaudu sisään kaaviaksesi — se ylittää valtuutusrajan
  • Käsittele yritystiedot (nimi/osoite/puhelin/arvosana) julkisena faktatietona; käsittele arvostelutekstiä arkaluonteisempana

Kysy tarvittaessa neuvoa lakiasiantuntijalta omaan tilanteeseesi.

Loppusanat

Kolme polkua, yksi tavoite.

Yelp Fusion API on valtuutettu ja vähän ylläpitoa vaativa vaihtoehto — mutta se rajoittuu kolmeen arvostelukatkelmaan ja alkaa $29/kk-hinnasta. Python-kaavinta antaa täyden hallinnan kaikkiin Yelp-datan kohtiin, mutta se vaatii oikeaa panostusta: curl_cffi TLS-imitointiin, residential-proxyt, satunnaiset viiveet, piilotetun JSONin parsinnan ja jatkuvan ylläpidon, kun Yelpin puolustukset kehittyvät. Thunderbit vie sinut “tarvitsen Yelp-dataa” -tilasta “tässä on taulukko” -tilaan noin 30 sekunnissa ilman koodia tai proxy-asetuksia.

Käytännössä vuonna 2025 toimivat estojen kierron peruspalikat: uskottavat otsikot täydellä Client Hints -sarjalla, curl_cffi TLS-fingerprintin jäljittelyyn, satunnaiset viiveet eksponentiaalisella backoffilla, residential-proxyjen kierto ja ennen kaikkea piilotetun JSONin (application/ld+json ja react-root-props) parsinta hauraiden CSS-valitsimien sijaan.

Etkö ole varma, mikä polku sopii? Kokeile ensin Thunderbitin ilmaista tasoa. Jos se riittää, säästät itseltäsi tunteja. Jos tarvitset enemmän hallintaa — täyden ohjelmallisen putken, omat kentät, tiukan CRM-integraation — yllä oleva Python-opas kattaa sen. Ja jos haluat syvemmän katsauksen kaavintatyökalujen kenttään, tutustu koontiimme parhaista Chrome-laajennuksista web-kaavintaan tai oppaaseemme datan kaapimisesta verkkosivuilta Exceliin.

Kokeile Thunderbitiä Yelp-datan poimintaan Get Started Free

Usein kysytyt kysymykset

Voinko kaapia Yelp-dataa Pythonilla ilmaiseksi?

Kyllä — käyttämällä ilmaisia kirjastoja kuten curl_cffi, parsel ja jmespath. Mutta oikeassa volyymissa (yli muutama kymmenen sivua) tarvitset maksulliset residential-proxyt, joiden hinnat alkavat noin $1.75/GB IPRoyalilla. Thunderbit tarjoaa myös ilmaisen tason, jossa saa 6 sivua kuukaudessa nopeaan koodittomaan poimintaan.

Estääkö Yelp kaavimet?

Kyllä, aggressiivisesti. Yelp käyttää TLS/JA3-fingerprintingia, IP-maineen pisteytystä, CAPTCHA:ita, käyttäytymisanalyysiä ja kiertäviä obfuskoituja CSS-luokkia. Tavallinen requests jää kiinni ensimmäisellä osumalla. Tämän oppaan kerroksellinen estojen kiertostrategia — curl_cffi TLS-imitointiin, uskottavat otsikot, satunnaiset viiveet ja residential-proxyt — on se, mikä toimii vuonna 2025.

Onko Yelp Fusion API parempi kuin kaavinta?

Riippuu tarpeesta. API on valtuutettu ja matalan riskin vaihtoehto, mutta se palauttaa vain 3 noin 160 merkin mittaista arvostelukatkelmaa, rajoittaa hakutulokset 240:een ja alkaa $29/kk-hinnasta. Jos tarvitset koko arvostelutekstin, arvostelun metatiedot tai enemmän kuin muutaman sadan tietueen päivässä, kaavinta on ainoa vaihtoehto.

Miten kaavin Yelp-arvostelut Pythonilla?

Käytä curl_cffiimpersonate="chrome131" -asetuksella hakeaksesi yrityssivun, poimi koodattu yritystunniste <meta name="yelp-biz-id">-tagista ja tee sitten POST-pyyntö osoitteeseen https://www.yelp.com/gql/batch käyttäen GetBusinessReviewFeed-operaatiota sekä sivuta base64-koodatun after-cursorin avulla. Vaiheittainen koodi on ylempänä oppaan opetusosiossa. Myös Scrapfly Yelp scraper repo on hyvä viiteimplementaatio.

Voinko kaapia Yelp-dataa ilman koodausta?

Kyllä — Thunderbitin AI Web Scraper sisältää valmiit Yelp-yritys ja arvostelu -pohjat. Avaa Yelp-sivu, klikkaa AI Suggest Fields ja sitten Scrape. Vienti Google Sheetiin, Exceliin, Airtableen ja Notioniin on ilmainen kaikilla tasoilla, myös ilmaisella suunnitelmalla.

Lue lisää

Shuai Guan
Shuai Guan
Thunderbitin toimitusjohtaja | AI:n ja tiedon automaation asiantuntija Shuai Guan on Thunderbitin toimitusjohtaja ja Michiganin yliopiston insinööritieteiden alumni. Lähes kymmenen vuoden kokemuksella teknologian ja SaaS-arkkitehtuurin parissa hän on erikoistunut muuttamaan monimutkaiset tekoälymallit käytännöllisiksi, koodittomiksi tiedon poimintatyökaluiksi. Tässä blogissa hän jakaa suodattamattomia, kentällä koeteltuja näkemyksiä verkkosivujen datan keruusta ja automaatiostrategioista, jotta voit rakentaa älykkäämpiä, dataohjautuvia työnkulkuja. Kun hän ei optimoi tietotyönkulkuja, hän hyödyntää samaa tarkkuutta myös valokuvauksen parissa.
Sisällysluettelo

Poimi verkkosivu pelkällä pyynnöllä

Kerro mitä tarvitset selkeällä englannilla. Tai vielä parempaa, älä kerro mitään.

Kokeile Thunderbitiä ilmaista
Poimi dataa AI:n avulla
Siirrä data helposti Google Sheetiin, Airtableen tai Notioniin
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week