Важно: этот гайд посвящён только публично доступным данным Yelp — тем, что видны анонимному посетителю без авторизации. Скрапинг может нарушать Terms of Service Yelp; в США чрезмерное автоматизированное обращение к защищённым системам может подпадать под Computer Fraud and Abuse Act (CFAA), а в ЕС персональные данные из отзывов регулируются GDPR. Перед запуском продакшен-сбора проконсультируйтесь с юристом и рассмотрите официальный Yelp Fusion API.
Если вы строите локальный бизнес-датасет — каталоги ресторанов, салонов, автосервисов вместе с рейтингами и отзывами — Yelp остаётся одним из самых ценных источников. Но в 2026 году «как скрапить Yelp» — это не вопрос парсинга HTML, а вопрос обхода антибот-системы PerimeterX/HUMAN, управления TLS-фингерпринтами и правильного выбора прокси. В этом гайде разберём, что именно доступно публично, как Yelp защищается, и как собрать бизнес-листинги и отзывы, не получая бан на первых 10 запросах.
Как скрапить Yelp в 2026: что доступно без авторизации
Yelp публикует значительный объём бизнес-данных на публичных страницах без логина. Каждое заведение имеет профиль по адресу https://www.yelp.com/biz/<slug>, где slug — это URL-идентификатор вида blue-bottle-coffee-austin. Без аккаунта и без cookies вы видите:
- Название, рейтинг (1–5 звёзд), количество отзывов и категорию бизнеса.
- Адрес, телефон, часы работы, включая сезонные исключения.
- Тексты отзывов — обычно первые ~100 отзывов доступны анонимно, остальные скрываются за кнопкой «see more» и подгрузкой.
- Фотографии от пользователей и владельца бизнеса.
- Атрибуты — «takes reservations», «outdoor seating», «wheelchair accessible» и т. п.
Официальный Yelp Fusion API даёт доступ к бизнес-поиску и деталям, но возвращает максимум 3 отзыва на бизнес через endpoint /businesses/{id}/reviews. Если вам нужен полный корпус отзывов для анализа тональности, обучения моделей или мониторинга репутации — Fusion API не покроет потребность, и единственный легальный путь — сбор публично видимых страниц.
Важно: данные за логином (личные сообщения, расширенная история отзывов конкретного пользователя, некоторые фотоальбомы) не входят в этот гайд. Их скрапинг нарушает ToS и в США может подпадать под CFAA.
Антибот-защита Yelp: PerimeterX/HUMAN, _px3 и TLS-фингерпринтинг
Yelp использует PerimeterX (ныне HUMAN Security) — одну из самых агрессивных антибот-платформ на рынке. PerimeterX работает на нескольких уровнях:
1. Cookie _px3 и sensor challenge
При первом запросе PerimeterX выполняет JavaScript-«sensor challenge» — собирает данные о браузере (Canvas fingerprint, WebGL, шрифты, тайминги, mouse movements) и выпускает cookie _px3. Без валидного _px3 сервер Yelp либо отдаёт пустую страницу, либо редиректит на /px-captcha. Обычный requests.get() без headless-браузера этот challenge не пройдёт.
2. TLS-фингерпринтинг (JA3/JA4)
PerimeterX анализирует TLS ClientHello — наборы шифров, расширения, порядок curves — и сравнивает с сигнатурой заявленного User-Agent. Если вы шлёте UA Chrome 120, но JA3 соответствует Python requests (на базе urllib3/OpenSSL), запрос помечается как бот. По данным исследований BrowserLeaks TLS, JA3-хеш Python requests стабильно отличается от Chrome на 100%.
3. IP-репутация и скоринг
PerimeterX ведёт репутационную базу IP. Datacenter-диапазоны (AWS, DigitalOcean, OVH, Hetzner) имеют низкий «trust score» — после 5–20 запросов с одного datacenter IP вы получаете CAPTCHA или 403. Резидентные IP от крупных ISP (Comcast, AT&T, Verizon) имеют высокий trust score и проходят значительно дольше.
4. CAPTCHA после нескольких datacenter-запросов
На практике: с datacenter-прокси без ротации первые 5–15 запросов могут пройти, затем — CAPTCHA. С резидентными IP и разумным темпом (1–2 запроса/сек на сессию) можно собирать тысячи страниц до первого блока, а ротация между запросами снижает риск ещё сильнее.
Почему нужны ротационные резидентные прокси с гео-таргетингом по США
Две причины делают резидентные прокси с US-гео стандартом для скрапинга Yelp:
- IP-репутация. PerimeterX скорит по IP-классу. Резидентные IP от американских ISP имеют trust score в 3–5 раз выше datacenter-IP по оценкам антифрод-вендоров. Это напрямую влияет на количество запросов до CAPTCHA.
- Локализация результатов. Yelp отдаёт разные бизнес-листинги в зависимости от гео IP-посетителя. Запрос
/search?find_desc=coffee&find_loc=Austin,+TXс IP из Германии может вернуть искажённые результаты или триггерить дополнительную проверку. IP из Остин, TX (-country-US-city-austin) даёт корректные локальные результаты.
Mobile-прокси (4G/5G) тоже имеют высокую репутацию, но обычно стоят дороже и дают большую задержку (300–800ms против 80–200ms у резидентных). Для Yelp оптимальны именно резидентные.
Сравнение типов прокси для скрапинга Yelp:
| Тип прокси | Репутация у PerimeterX | Задержка | Цена | Гео-таргетинг по городу | Подходит для Yelp |
|---|---|---|---|---|---|
| Datacenter | Низкая | 20–50ms | Низкая | Ограниченный | Нет — быстрые блоки |
| Residential | Высокая | 80–200ms | Средняя | Да (страна/город) | Да — оптимально |
| Mobile (4G/5G) | Очень высокая | 300–800ms | Высокая | Да (страна) | Да, но дороже |
Подобрать гео и оценить стоимость можно на странице локаций ProxyHat и на странице тарифов.
Архитектура скрапера: review_feed JSON и __INITIAL_STATE__
Вместо парсинга HTML регулярками или BeautifulSoup, эффективнее извлекать данные из встроенных JSON-блобов, которые Yelp рендерит в страницу для гидратации React-приложения. Два ключевых источника:
window.__INITIAL_STATE__— большой JSON-объект в теге<script>, содержит бизнес-профиль, первые отзывы, категории, фото.- review_feed — JSON-эндпоинт вида
/biz/<slug>?q=&rl=en&sort_by=relevance_descили AJAX-эндпоинт/async/<slug>/review_feed, отдаёт пагинированные отзывы.
Извлечение __INITIAL_STATE__ одним regex-матчем над HTML быстрее и надёжнее, чем 50 CSS-селекторов. Для пагинации отзывов используется review_feed с параметром start (offset) и limit.
Пример 1: Python requests + ProxyHat HTTP-шлюз
Ниже — рабочий скелет на Python, использующий ротационные резидентные прокси ProxyHat через HTTP-шлюз gate.proxyhat.com:8080 с гео-таргетингом по Остину, TX. Скрипт извлекает __INITIAL_STATE__ и парсит один truncated-объект отзыва.
import re, json, time, random
import requests
from urllib.parse import quote
PROXY = "http://user-country-US-city-austin:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY, "https": PROXY}
UA_POOL = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
]
def fetch_biz(slug: str, session_id: str | None = None) -> dict:
user = f"user-country-US-city-austin"
if session_id:
user += f"-session-{session_id}"
proxy = f"http://{user}:PASSWORD@gate.proxyhat.com:8080"
proxies = {"http": proxy, "https": proxy}
url = f"https://www.yelp.com/biz/{slug}"
headers = {
"User-Agent": random.choice(UA_POOL),
"Accept-Language": "en-US,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}
r = requests.get(url, proxies=proxies, headers=headers, timeout=30)
if r.status_code != 200 or "px-captcha" in r.text.lower():
raise RuntimeError(f"Blocked or captcha: status={r.status_code}")
# Извлекаем __INITIAL_STATE__
m = re.search(r"window\.__INITIAL_STATE__\s*=\s*({.*?});?</script>",
r.text, re.DOTALL)
if not m:
raise RuntimeError("__INITIAL_STATE__ not found")
state = json.loads(m.group(1))
# Бизнес-профиль
biz = state.get("bizDetailsPageProps", {}).get("businessContent", {})
name = biz.get("name", "")
rating = biz.get("rating", 0)
review_count = biz.get("reviewCount", 0)
# Первый truncated-объект отзыва
reviews = state.get("bizDetailsPageProps", {}) \
.get("reviewFeedQuery", {}).get("reviews", [])
first_review = {
"id": reviews[0].get("id", "") if reviews else "",
"author": reviews[0].get("author", {}).get("displayName", "") if reviews else "",
"rating": reviews[0].get("rating", 0) if reviews else 0,
"text": (reviews[0].get("comment", {}).get("text", "")[:200] + "…") if reviews else "",
"date": reviews[0].get("localizedDate", "") if reviews else "",
}
return {
"name": name,
"rating": rating,
"review_count": review_count,
"first_review": first_review,
}
if __name__ == "__main__":
result = fetch_biz("blue-bottle-coffee-austin", session_id="biz1-abc123")
print(json.dumps(result, indent=2, ensure_ascii=False))
time.sleep(random.uniform(1.0, 2.5)) # pacing
Что делает этот код:
- Использует
-country-US-city-austinдля локализованных результатов из Остина. - Опциональный
-session-{id}включает sticky-сессию — один IP на всё время пагинации отзывов. - Ротирует User-Agent между двумя реальными Chrome-строками.
- Извлекает
__INITIAL_STATE__одним regex, парсит первый truncated-объект отзыва (текст обрезан до 200 символов). - Спит 1.0–2.5 секунды между запросами для pacing.
Пример 2: Node.js + SOCKS5 на порту 1080
Для Node.js используем SOCKS5-шлюз ProxyHat на порту 1080 и библиотеку socks-proxy-agent:
const { SocksProxyAgent } = require('socks-proxy-agent');
const fetch = require('node-fetch');
const PROXY_URL = 'socks5://user-country-US-city-austin:PASSWORD@gate.proxyhat.com:1080';
const agent = new SocksProxyAgent(PROXY_URL);
const UA_POOL = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' +
'(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ' +
'(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
];
async function fetchBiz(slug, sessionId) {
let user = 'user-country-US-city-austin';
if (sessionId) user += `-session-${sessionId}`;
const agent = new SocksProxyAgent(
`socks5://${user}:PASSWORD@gate.proxyhat.com:1080`
);
const url = `https://www.yelp.com/biz/${slug}`;
const headers = {
'User-Agent': UA_POOL[Math.floor(Math.random() * UA_POOL.length)],
'Accept-Language': 'en-US,en;q=0.9',
};
const res = await fetch(url, { agent, headers, timeout: 30000 });
const html = await res.text();
if (html.toLowerCase().includes('px-captcha')) {
throw new Error('Blocked by PerimeterX');
}
const m = html.match(/window\.__INITIAL_STATE__\s*=\s*({.*?});?<\/script>/s);
if (!m) throw new Error('__INITIAL_STATE__ not found');
const state = JSON.parse(m[1]);
const reviews = state.bizDetailsPageProps?.reviewFeedQuery?.reviews ?? [];
const first = reviews[0] ?? {};
console.log(JSON.stringify({
name: state.bizDetailsPageProps?.businessContent?.name,
rating: state.bizDetailsPageProps?.businessContent?.rating,
review_count: state.bizDetailsPageProps?.businessContent?.reviewCount,
first_review: {
id: first.id,
author: first.author?.displayName,
rating: first.rating,
text: (first.comment?.text ?? '').slice(0, 200) + '…',
},
}, null, 2));
}
fetchBiz('blue-bottle-coffee-austin', 'biz1-abc123')
.then(() => new Promise(r => setTimeout(r, 1500)));
SOCKS5 полезен, когда нужно туннелирование на транспортном уровне или когда HTTP-CONNECT блокируется промежуточным файрволом. Для большинства задач Yelp HTTP-шлюз на 8080 проще и достаточно быстр.
Пагинация отзывов и rate-limit pacing
Полный корпус отзывов требует пагинации. Yelp отдаёт отзывы порциями через review_feed с offset-параметром. Стратегия:
- Sticky-сессия на весь пагинационный цикл. Используйте
-session-{biz_id}в username, чтобы все запросы для одного бизнеса шли с одного IP. Смена IP посреди пагинации выглядит подозрительно для PerimeterX. - Параметр
startс шагом 10. Yelp обычно отдаёт по 10 отзывов на страницу. Превышение offset ~990 часто возвращает пустой список — это мягкий лимит для анонимных пользователей. - Pacing 1–2 запроса/сек на сессию. Случайный jitter 1.0–2.5 секунды между запросами снижает обнаружение. Не делайте 10 запросов/сек — даже резидентный IP получит CAPTCHA.
- Пауза между бизнесами. После завершения одного бизнеса — пауза 5–15 секунд и смена session-ID (новый IP).
def scrape_all_reviews(slug, max_pages=100):
all_reviews = []
session_id = f"{slug}-{int(time.time())}"
for page in range(max_pages):
start = page * 10
data = fetch_review_feed(slug, start=start, session_id=session_id)
reviews = data.get("reviews", [])
if not reviews:
break
all_reviews.extend(reviews)
time.sleep(random.uniform(1.2, 2.5))
return all_reviews
Ротация User-Agent и снижение fingerprint-риска
User-Agent — не единственный фингерпринт, но самый очевидный. Правила:
- Используйте реальные, актуальные UA. Chrome 120, Safari 17, Firefox 121. Устаревшие UA (Chrome 83) сразу подозрительны.
- Согласованный набор заголовков. Если UA — Chrome на Windows, заголовки
Sec-CH-UA,Sec-CH-UA-Platformдолжны совпадать. Несогласованность = флаг. - Ротируйте UA вместе с IP. Новый IP + новый UA на каждый бизнес — естественнее, чем один UA на 1000 IP.
- Accept-Language соответствует гео. Для US-IP используйте
en-US,en;q=0.9, неru-RU.
Более продвинутый подход — headless-браузер (Playwright/Puppeteer) с stealth-плагинами для прохождения sensor challenge. Это медленнее (3–8 сек на страницу), но надёжнее для сайтов с агрессивным PerimeterX. Базовый requests + резидентные прокси работает для большинства публичных страниц Yelp, если темп разумный.
Типичные ошибки и edge-кейсы
- Игнорирование
_px3cookie. Если вы не сохраняете cookies между запросами в рамках сессии, PerimeterX видит «нового» посетителя каждый раз и чаще триггерит challenge. Используйтеrequests.Session(). - Слишком высокий темп. 10 запросов/сек с datacenter IP = бан за 30 секунд. Даже 5 запросов/сек с резидентного IP повышает риск. Цель — 1–2/сек.
- Один IP на весь датасет. 10 000 страниц с одного IP = гарантированный бан. Ротация между бизнесами обязательна.
- Парсинг HTML вместо JSON-блобов. CSS-селекторы ломаются при каждом редизайне Yelp.
__INITIAL_STATE__стабилен месяцами. - Игнорирование robots.txt. robots.txt Yelp запрещает часть путей. Проверяйте перед сбором.
- Сохранение персональных данных без анонимизации. Имя автора отзыва + дата + город = персональные данные под GDPR. Храните хеш или псевдонимизируйте.
Этический скрапинг и когда предпочесть официальный API
Скрапинг публичных данных — серая зона. Юридический ландшафт: в США прецедент hiQ Labs v. LinkedIn (9th Circuit, 2022) поддержал скрапинг публично доступных данных как законный, но CFAA всё ещё применяется к «exceeding authorized access». В ЕС GDPR регулирует любые персональные данные, включая имена авторов отзывов.
Практические принципы этичного скрапинга Yelp:
- Собирайте только публичные страницы без логина. Данные за авторизацией — вне границ.
- Уважайте
robots.txt. Если путь запрещён — не скрапьте. - Ограничьте темп. 1–2 запроса/сек — это вежливо. 50 запросов/сек — это DoS.
- Анонимизируйте персональные данные. Для аналитики тональности имя автора обычно не нужно — достаточно текста и рейтинга.
- Предпочитайте Fusion API, где он покрывает потребность. Если вам нужны только бизнес-профили и 3 отзыва — используйте официальный API. Это легально, стабильно и не требует прокси.
- Не перепродавайте данные как есть. ToS Yelp запрещает редистрибуцию. Агрегированные метрики, производные инсайты — серая зона, сырая перепродажа — нарушение.
Когда Fusion API достаточно: бизнес-поиск по гео, базовые детали, 3 отзыва на бизнес, категории, часы. Когда нужен скрапинг: полный корпус отзывов (>3), фотографии в высоком разрешении, исторические изменения рейтингов, атрибуты не из API.
Подробнее о паттернах скрапинга и пагинации — в нашем гайде по веб-скрапингу и SERP-трекингу. Документация ProxyHat — на docs.proxyhat.com.
Key Takeaways
- Публичные страницы Yelp (
/biz/<slug>) отдают бизнес-профиль, рейтинг, категории, часы и ~100 отзывов без логина. Fusion API ограничен 3 отзывами. - PerimeterX/HUMAN — основная защита:
_px3cookie, TLS-фингерпринтинг (JA3/JA4), IP-скоринг. Datacenter-IP получают CAPTCHA после 5–20 запросов. - Ротационные резидентные прокси с US-гео (
-country-US-city-austin) — оптимальный выбор: высокая IP-репутация и локализованные результаты. - Извлекайте
__INITIAL_STATE__одним regex вместо парсинга HTML — стабильнее и быстрее. - Pacing 1–2 запроса/сек, sticky-сессии для пагинации, ротация UA вместе с IP — снижают fingerprint-риск.
- Этика: только публичные данные, уважение robots.txt, анонимизация персональных данных, предпочтение Fusion API где возможно.
FAQ
Можно ли скрапить Yelp без прокси?
Технически — да, первые 5–15 запросов с вашего IP пройдут. Но без ротации вы получите CAPTCHA или 403 в течение минуты, а ваш IP попадёт в репутационную базу PerimeterX. Для любого объёма выше 50 страниц прокси обязательны.
Чем отличается скрапинг от Fusion API?
Fusion API — официальный, легальный, с ключом доступа, но ограничен: 3 отзыва на бизнес, лимиты по запросам, нет фото в высоком разрешении. Скрапинг публичных страниц даёт полный корпус отзывов, но нарушает ToS и требует обхода PerimeterX.
Сколько отзывов доступно без логина?
Обычно ~100 отзывов на бизнес видны анонимно. После offset ~990 review_feed часто возвращает пустой список. Для большего объёма нужен логин — но это уже нарушает ToS и не покрывается этим гайдом.
Какой темп запросов безопасен?
1–2 запроса в секунду на сессию с jitter 1.0–2.5 сек. Между разными бизнесами — пауза 5–15 секунд и смена session-ID (новый IP). 10 запросов/сек = гарантированный бан даже с резидентных прокси.
Нужно ли использовать headless-браузер?
Для большинства публичных страниц Yelp достаточно requests + резидентные прокси + извлечение __INITIAL_STATE__. Headless (Playwright/Puppeteer со stealth-плагинами) нужен, если PerimeterX начинает требовать полноценный sensor challenge — это происходит при высоком темпе или подозрительных паттернах.






