Booking.com через IPv6 прокси: парсинг цен на отели и авиабилеты
Содержание
- Почему Booking.com и IPv6 — это отдельная головная боль
- Как Booking определяет, что вы бот
- IPv6-прокси: чем отличается от IPv4 в контексте парсинга
- Архитектура пайплайна для сбора цен
- Работа с геозависимыми ценами
- Проблема с TLS fingerprint
- Ротация IPv6 внутри /64
- !/bin/bash
- Кейс: парсинг отелей Стамбула
- Кейс: авиабилеты через Booking
- Сравнение с конкурентами
- Юридическая сторона
- Итоги и рекомендации
Почему Booking.com и IPv6 — это отдельная головная боль
Booking.com — один из самых агрессивно защищённых сайтов в сфере travel. Cloudflare, Akamai, собственная антибот-система, fingerprinting на уровне TLS. Плюс к этому — геозависимые цены. Один и тот же отель в Стамбуле покажет 87 EUR с немецкого IP и 112 EUR с турецкого. Разница в 28% — не баг, а бизнес-логика.
С IPv4 всё понятно: пул адресов, ротация, бан после N запросов. С IPv6 другая история. Провайдер выдаёт /64 — это 18 квинтиллионов адресов. Ротация внутри подсети выглядит для антибота как «много разных пользователей из одной локации». Иногда это прокатывает. Иногда — нет.
Booking смотрит не только на IP. Он смотрит на ASN, на поведение подсети в целом, на то, сколько уникальных сессий пришло с /64 за последний час. Если 5000 — подозрительно. Если 50 — нормально.
Как Booking определяет, что вы бот
Три уровня защиты работают параллельно. Первый — Cloudflare с JS-challenge. Второй — собственный WAF Booking, который анализирует заголовки, порядок их отправки, TLS fingerprint (JA3/JA4). Третий — поведенческий анализ: скорость кликов, движение мыши, время между запросами.
JA3-хеш curl и Python requests отличаются от Chrome. Это видно сразу. Booking не блокирует мгновенно — он даёт «отравленные» ответы. Цены показываются завышенные, availability — ложное. Вы парсите мусор и не понимаете, почему.
```
curl -6 -s 'https://www.booking.com/searchresults.html?ss=Berlin&checkin=2025-03-15&checkout=2025-03-18' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' \
-H 'Accept-Language: en-US,en;q=0.9' \
--compressed -o result.html
```
Этот запрос вернёт 200 OK. Но в HTML не будет цен — только skeleton-загрузка. Реальные данные подтягиваются через XHR к `/dml/graphql`. И вот там начинается настоящая проверка.
IPv6-прокси: чем отличается от IPv4 в контексте парсинга
IPv4-прокси — дефицитный ресурс. Один адрес, много клиентов, высокая вероятность попасть в чёрный список. IPv6 — обратная ситуация. Адресов столько, что можно выделить /64 на одну задачу и ротировать внутри.
Но есть нюанс. Многие сайты (и Booking в том числе) применяют более строгие rate limits к IPv6-подсетям. Логика: если с /64 идёт 10 000 запросов в час — это точно автоматизация. С /64 реальных пользователей столько не бывает.
Практика: ротация внутри /64 работает, если не превышать 200-300 запросов в час на подсеть. Хотите больше — нужен /48 или несколько /64 от разных провайдеров.
| Параметр | IPv4 residential | IPv6 datacenter | IPv6 residential |
|---|---|---|---|
| Стоимость за IP | \$1-3 | \$0.01-0.05 | \$0.10-0.30 |
| Скорость бана Booking | 2-5 часов | 15-40 минут | 4-12 часов |
| Поддержка гео | Высокая | Средняя | Высокая |
| Размер пула | /24 = 256 | /64 = 18.4 квинтиллиона | /64 |
Архитектура пайплайна для сбора цен
Прямой парсинг HTML Booking — тупик. Страница рендерится на клиенте, данные приходят через GraphQL. Значит, нужен headless-браузер или реверс GraphQL-запросов.
Headless Chrome через Playwright — работает, но медленно. 3-8 секунд на страницу. При 10 000 отелей это 8-22 часа. Плюс каждый браузерный инстанс жрёт 200-400 МБ RAM.
Реверс GraphQL быстрее — 300-800 мс на запрос. Но требует разбора токенов, которые Booking меняет раз в несколько недель.
```python
import httpx
import asyncio
async def fetch_prices(hotel_id: str, proxy: str):
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15",
"Accept": "application/json",
"Content-Type": "application/json",
"X-Booking-Csrf-Token": "TOKEN_HERE",
}
payload = {
"operationName": "StaysSearch",
"variables": {"hotelId": hotel_id, "checkin": "2025-03-15"},
"query": "query StaysSearch(\$hotelId: String!, \$checkin: String!) { ... }"
}
async with httpx.AsyncClient(proxy=proxy, timeout=15.0) as client:
r = await client.post(
"https://www.booking.com/dml/graphql",
json=payload, headers=headers
)
return r.json()
```
Прокси-слой: пул IPv6-адресов, распределение по подсетям, контроль rate limit на /64. Без этого всё упирается в бан через 20-30 минут.
Работа с геозависимыми ценами
Booking показывает разные цены в зависимости от:
- страны IP (определяется по GeoIP)
- валюты в заголовке `Accept-Language` и cookie
- наличия cookie с предыдущими сессиями
- user-agent (мобильный vs десктопный)
Чтобы получить «честную» цену для конкретного рынка, нужно совпадение всех параметров. Немецкий IP + `Accept-Language: de-DE` + валюта EUR. Иначе получите цену в долларах с наценкой за конвертацию.
Пример: отель в Берлине, 3 ночи в марте.
- IP Германия, EUR: 342 EUR
- IP США, USD: 389 USD (= 358 EUR по курсу)
- IP Турция, TRY: 12 400 TRY (= 335 EUR)
Разница между США и Германией — 4.7%. Не критично, но при парсинге 50 000 отелей набегает.
Для авиабилетов ситуация жёстче. Google Flights и Skyscanner показывают разницу до 30% в зависимости от точки входа. Booking (через Kiwi.com) — до 15%.
Проблема с TLS fingerprint
Booking использует JA4-фингерпринтинг. Python `requests` и `httpx` имеют отличный от браузеров TLS handshake. Это палево.
Решения:
1. `curl_cffi` — библиотека, имитирующая TLS-отпечаток Chrome/Firefox
2. Playwright с реальным браузером
3. Кастомный TLS-стек на Go с настройкой cipher suites
```python
from curl_cffi import requests
r = requests.get(
"https://www.booking.com/hotel/de/adlon-kempinski.html",
impersonate="chrome124",
proxies={"https": "http://[2001:db8::1]:8080"},
headers={"Accept-Language": "de-DE,de;q=0.9"}
)
```
`impersonate="chrome124"` подставляет TLS ClientHello, HTTP/2 settings, порядок заголовков — всё как у реального Chrome 124. JA4-хеш совпадает. Booking видит обычного пользователя.
Без этого — 403 через 10-15 запросов. С этим — 200 OK на протяжении тысяч запросов, если не нарушать rate limit.
Ротация IPv6 внутри /64
Стратегия зависит от объёма. Для 1000-5000 запросов в час хватает одного /64 с ротацией каждые 20-50 запросов. Для 50 000+ нужен /48 или пул /64 от разных провайдеров.
Ключевая метрика — «свежесть» адреса. Если адрес использовался 3 дня назад и получил капчу — Booking его помнит. Нужен cooldown минимум 7-14 дней.
```bash
!/bin/bash
PREFIX="2001:db8:1234::"
for i in \$(seq 1 1000); do
ADDR="\${PREFIX}\${i}"
curl -6 --interface "\$ADDR" -s -o /dev/null -w "%{http_code}\n" \
"https://www.booking.com/" &
done
wait
```
Этот скрипт запускает 1000 параллельных запросов с разных адресов одной /64. Booking ответит 200 на первые 200-300. Остальные — 429 или 403. Оптимально — 50 параллельных с задержкой 1-2 секунды.
Кейс: парсинг отелей Стамбула
Задача: собрать цены на 2500 отелей Стамбула на 14 дат. Итого 35 000 запросов.
Первая попытка: IPv4 datacenter-прокси, 100 потоков. Результат: 400 успешных, остальные — 403 или капча. Причина: datacenter ASN (DigitalOcean, Hetzner) в чёрном списке Booking. Плюс высокая скорость — 100 запросов в секунду с одного /24.
Вторая попытка: IPv6 residential от турецкого провайдера, /56 подсеть. 20 потоков, задержка 800-1200 мс. Результат: 31 200 успешных из 35 000 (89%). Баны начались после 18 000 запросов — Booking пометил /56 как подозрительную. Пришлось разбить на 4 подсети и снизить скорость до 10 запросов в секунду.
Третья попытка: та же схема + `curl_cffi` с impersonate Chrome. Успешность 97%. Оставшиеся 3% — отели без доступных номеров на выбранные даты (Booking возвращает пустой ответ, не ошибку).
Время выполнения: 4 часа 20 минут на 35 000 запросов. Средняя задержка — 440 мс.
Кейс: авиабилеты через Booking
Booking продаёт авиабилеты через партнёрство с Kiwi.com. API отличается от отельного. Эндпоинт `/flights/search` требует другой набор токенов и работает только с определёнными гео.
Проблема: с российских и турецких IP поиск авиабилетов часто возвращает пустой результат. Booking ограничивает функционал по региону. С немецких и американских — работает.
Решение: IPv6-прокси из Германии, Франкфурт. Провайдер — Deutsche Telekom residential. /64 подсеть, ротация каждые 30 запросов. Результат: 94% успешных ответов, средняя задержка 620 мс.
Важный момент: Booking throttles flight search жёстче, чем отели. Лимит — примерно 300 запросов в час на /64. Выше — 429 с `Retry-After: 3600`.
Сравнение с конкурентами
Booking — не единственный источник. Для полноты картины нужны Expedia, Agoda, Hotels.com. Каждый имеет свои особенности.
| Сайт | Защита | IPv6-политика | Средняя задержка |
|---|---|---|---|
| Booking.com | Cloudflare + JA4 | Умеренная | 400-800 мс |
| Expedia | Akamai | Строгая | 600-1200 мс |
| Agoda | Собственная | Лояльная | 300-600 мс |
| Hotels.com | Cloudflare | Умеренная | 500-900 мс |
Agoda самая лояльная к IPv6. Expedia — самая строгая, банит /64 после 100 запросов. Booking в середине.
Юридическая сторона
Парсинг публичных цен — серая зона. Booking в ToS прямо запрещает автоматизированный сбор. На практике — судятся редко, но блокируют активно. Если планируете коммерческое использование — нужен юридический анализ в вашей юрисдикции.
Технически: не создавайте нагрузку, эквивалентную DDoS. 10-20 запросов в секунду с одной подсети — безопасно. 1000 — гарантированный бан и возможные письма от юристов.
Итоги и рекомендации
IPv6 для парсинга Booking работает. Но не «просто IPv6», а правильно настроенный пул с ротацией, контролем rate limit и имитацией браузерного TLS.
Минимальный стек: `curl_cffi` + IPv6 residential прокси + ротация внутри /64 каждые 20-30 запросов + задержка 500-1000 мс между запросами. Это даёт 90-97% успешных ответов.
Если нужны цены для конкретного рынка — совпадение IP-гео, языка и валюты обязательно. Иначе получите искажённые данные.
Для промышленных объёмов (100 000+ запросов в день) — несколько /48 подсетей от разных провайдеров, распределение нагрузки, мониторинг банов в реальном времени. Один /64 не выдержит.