Назад в Центр знаний
Сеть

Доступность на Booking.com: календарь по датам

Моделируйте доступность как календарь с ключом по дате, где номер и тариф это измерения, записывайте запрос, который проецирует страница, и держите пять состояний на ячейку.

BotBrowser Team

Документация

Нужна структурированная документация по теме Сеть?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

Сбор доступности на Booking.com это не задача извлечения документов, потому что страница доступности не является документом. Это проекция запроса: даты, размещение, номер и тариф, которые вы запросили, определяют, какие ячейки календаря вообще появятся на странице. BotBrowser документирует географически согласованный выход и значения локали из профиля, поэтому сравнение точки продажи может объявить представляемый регион и язык. Он не предоставляет данные доступности, не держит инвентарь, не бронирует номер и не гарантирует, что запрос дважды вернёт один и тот же календарь. Там, где есть официальный партнёрский или партнёрский по программе фид, используйте его.

Сконструированное проживание с 2026-12-10 по 2026-12-13 проецируется в три строки дат, где номер и тариф являются измерениями каждой строки, пять возможных состояний на ячейку и запись снимка, хранящая запрос рядом с наблюдением.

Кратко

  • Страница доступности это проекция своего запроса. Записывайте запрос, иначе страницу нельзя будет истолковать позже.
  • Ключ календаря это дата, а не страница. Проживание на три ночи это три строки дат, а дата выезда исключается.
  • Номер и тариф это измерения строки, а не отдельные календари. Два тарифа на одну дату это две ячейки, а не два наблюдения одной.
  • Используйте пять состояний на ячейку: наблюдаемая доступность, наблюдаемое закрытие, вне окна, отсутствие в ответе и непринятый ответ. Отсутствующая ячейка не означает закрытый номер.
  • Предпочитайте официальный партнёрский фид там, где он есть, и считайте условия платформы источником истины о том, что можно собирать.

Содержание

Доступность как календарь

Поиск жилья отвечает на вопрос о диапазоне дат. Диапазон это единица, по которой источник назначает цену, а отдельная ночь это единица, по которой календарь может ставить ключ. Ошибка в этом отношении встречается чаще всего в работе с доступностью, потому что страница с надписью «от 412» за три ночи выглядит как одно значение, тогда как это сводка трёх строк, каждая из которых может нести разную доступность.

Дата выезда исключается. Проживание с 2026-12-10 по 2026-12-13 занимает ночи 10, 11 и 12, а гость выезжает 13-го. Если считать дату выезда четвёртой ночью, календарь смещается на единицу для каждого проживания, и ошибка незаметна, пока кто-то не сравнит двухночное и трёхночное бронирование одного и того же номера.

Доступность также не является свойством объекта целиком. Отель может иметь свободные номера, когда конкретный тип распродан, и тип может быть свободен, когда тариф с завтраком закрыт. Поэтому календарю нужно как минимум два измерения, прежде чем ячейка что-то означает.

Ключ и измерения

Ключ это дата плюс то, что наблюдается. Измерения описывают, как это наблюдение было квалифицировано. Их разделение и позволяет сравнивать два снимка, не смешивая молча тип номера, тарифный план или точку продажи.

ЧастьСодержимоеПочему нельзя свернуть в значение уровня страницы
date_keyДата ночи в ISO, в часовом поясе объектаДве ночи это два наблюдения, а не одно
room_codeТип номера или юнита, как его называет источникРаспроданный люкс не закрывает отель
rate_codeТарифный план, как его называет источникЗакрытый тариф не закрывает номер
occupancyВзрослые и дети, запрошенные в запросеРазмещение меняет предлагаемый инвентарь

Ключа (date, room, rate, occupancy) достаточно, чтобы сравнить два наблюдения одного и того же. Ключ только (date) сливает люкс и стандартный номер в одну ячейку, и полученный ряд будет показывать номер «открывающимся» каждый раз, когда меняется самая дешёвая категория. Ключ (page) сливает три ночи в одно значение и теряет способность сказать, какая ночь изменилась.

Часовой пояс объекта тоже входит в ключ, но как объявленное свойство календаря, а не как отдельное измерение. Ночь это локальное понятие, и снимок, сделанный через переход на летнее время без записи пояса, даст две строки, похожие на одну дублированную ночь.

Размещение заслуживает отдельной заметки, потому что оно меняет, какой инвентарь существует, а не только как он оценён. Запрос на двух взрослых может вернуть тип, который запрос на четырёх не увидит, и один и тот же физический номер может появиться как два разных предложения с разными тарифными кодами. Запись размещения рядом с номером и тарифом позволяет более позднему сравнению понять, пришло ли изменение из инвентаря или из заданного вопроса.

Правила минимального проживания это самое тихое измерение. Объект может требовать две ночи на выходных, поэтому запрос на одну ночь ничего не вернёт, хотя номер действительно свободен на две ночи. Календарь, который записывает такой запрос как observed_closed, фиксирует результат политики как факт доступности. Там, где страница объявляет минимальное проживание, записывайте его как измерение или как примечание; там, где нет, считайте пустой результат одной ночи наблюдением с объявленным запросом, а не закрытием.

Валюта и точка продажи стоят рядом с четырьмя тарифными входами, а не внутри ключа календаря. Тарифный код может существовать в нескольких валютах и по нескольким правилам точки продажи, и сумма будет различаться, пока доступность не меняется. Держите валюту и точку продажи в записи, чтобы сравнение цен не путали со сравнением доступности и чтобы смена валюты не выглядела как открывшийся номер.

Что страница проецирует из запроса

Документация MDN по URL API описывает URL как интерфейс, который разбирает и предоставляет компоненты адреса, включая параметры поиска. Это именно та часть поверхности браузера, которая нужна этой задаче: отрисованная страница доступности выбирается параметрами своего адреса, поэтому адрес это свидетельство о странице, а не украшение вокруг неё.

Два разных адреса могут описывать одно проживание. Диапазон дат можно записать двумя параметрами, одним параметром диапазона или сегментом пути, а запрос может добавлять параметры отслеживания, не меняющие результат. Поэтому нормализация запроса это первый шаг к сравнимости двух снимков, и она должна происходить до загрузки страницы, а не после.

// Constructed fixture: the same stay written two ways, then a changed check-in.
const raw = [
  'https://example.test/hotel/alpha?checkin=2026-12-10&checkout=2026-12-13&adults=2&tracking=abc',
  'https://example.test/hotel/alpha?stay=2026-12-10_2026-12-13&adults=2',
  'https://example.test/hotel/alpha?checkin=2026-12-11&checkout=2026-12-14&adults=2',
];
const KEEP = ['checkin', 'checkout', 'adults', 'children', 'room', 'rate'];

const lines = raw.map(input => {
  const url = new URL(input);
  const stay = url.searchParams.get('stay');
  const params = new Map();
  if (stay) {
    const [checkin, checkout] = stay.split('_');
    params.set('checkin', checkin);
    params.set('checkout', checkout);
  }
  for (const key of KEEP) {
    const value = url.searchParams.get(key);
    if (value) params.set(key, value);
  }
  const canonical = [...params.entries()]
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([k, v]) => `${k}=${v}`)
    .join('&');
  return `canonical=${canonical} key=${params.get('checkin')}..${params.get('checkout')}`;
});
console.log(lines.join('\n'));

Сконструированный вывод показывает, что первые два адреса сводятся к одному каноническому запросу, а третий остаётся отдельным, потому что его даты другие.

canonical=adults=2&checkin=2026-12-10&checkout=2026-12-13 key=2026-12-10..2026-12-13
canonical=adults=2&checkin=2026-12-10&checkout=2026-12-13 key=2026-12-10..2026-12-13
canonical=adults=2&checkin=2026-12-11&checkout=2026-12-14 key=2026-12-11..2026-12-14

Параметр отслеживания исчезает в первых двух строках, и это и есть цель: два снимка, отличающиеся только меткой кампании, описывают одно проживание и должны сравниваться как один. Третья строка сохраняет свой ключ, потому что сдвинутый заезд это другой вопрос, даже когда число ночей совпадает.

Три правила нормализации делают это поведение надёжным. Сортируйте сохраняемые параметры по имени, чтобы каноническая форма не зависела от порядка, который использовал сайт. Удаляйте параметры, значение которых не влияет на результат, и держите явный список тех, что влияют, чтобы новый параметр отслеживания не создавал молча новый ряд. Представляйте диапазон дат единственным способом, преобразуя параметр диапазона в две явные даты, чтобы выбор кодировки сайтом не протекал в ключ.

Есть и граница, которую нормализатор не пересечёт. Два разных на вид адреса могут описывать одно проживание через перенаправление, а два одинаковых на вид адреса могут разрешаться по-разному из-за cookie или состояния аккаунта. Поэтому канонический запрос это утверждение о запрошенном, а не гарантия отрисованного. Записывайте и канонический запрос, и итоговый адрес после перенаправления, и считайте расхождение между ними находкой, а не шумом.

Пять состояний на ячейку

Работа с доступностью чаще всего ломается на границе между «недоступно» и «не наблюдалось». Двоичная модель доступно/закрыто заставляет каждую отсутствующую ячейку попасть в один из двух ответов, и оба выбора неверны для ячейки, о которой запрос не спрашивал.

СостояниеЧто наблюдалосьЧто это подтверждает
observed_availableЗапрос вернул предложение для этой даты, номера и тарифаЯчейка была доступна в этом запросе в этот момент
observed_closedЗапрос вернул явный сигнал о распроданности или закрытииЯчейка была закрыта в этом запросе в этот момент
not_in_windowОкно запроса не включало эту датуНичего о ячейке; окно было ограничено
absent_in_windowОкно покрывало дату, но ответ не перечислил ячейкуНичего о ячейке; ответ её пропустил
unacceptedНет пригодного ответа: проверка, ошибка, тайм-аут, сбой разбораНичего о ячейке; наблюдение не удалось

Два состояния отсутствия спасают ряд от выдуманных закрытий и описывают разные сбои. Если снимок запросил только три ночи, четвёртая ночь это not_in_window: вне ограниченного окна и не закрыта. Если окно покрывало дату, но ответ не перечислил ячейку, это absent_in_window: внутри окна, не перечислена, всё равно не закрыта. Запись любого как закрытия заставляет объект выглядеть потерявшим доступность, о которой он никогда не сообщал.

Состояние unaccepted защищает от обратной ошибки. Страница проверки, ответ 500 и сбой разбора дают ноль ячеек, и трактовка их как пустой доступности превращает проблему инфраструктуры в наблюдение о предложении. Держите их в собственном состоянии, чтобы более поздний читатель видел, какая часть календаря действительно наблюдалась.

Документация MDN по Performance API описывает интерфейсы браузера для измерения времени и загрузки ресурсов. Здесь это важно только для границы между принятой и медленной страницей: снимок, сдавшийся до отрисовки календаря, должен быть записан как unaccepted, а не как объект без номеров. Запись времени, за которое страница пришла в устойчивое состояние, рядом с состоянием делает это различие проверяемым.

Есть отдельное условие вне пяти состояний, которое не следует в них сворачивать: календарь наблюдался, но наблюдение относится к другому охвату, чем заявляет ряд. Снимок с корпоративным тарифным кодом, входом участника или промокампанией может показывать доступность, которой у публичного ряда нет, и смешение даёт строки, выглядящие сравнимыми и не являющиеся такими. Записывайте охват рядом с запросом и начинайте новый ряд при смене охвата.

Пяти состояниям нужно и правило пересмотра. Ячейка, наблюдавшаяся доступной в понедельник и закрытой во вторник, это переход, а не противоречие, и запись должна хранить обе строки с их временем наблюдения, а не перезаписывать первую. Перезапись теряет переход и не даёт отличить реальное изменение от исправления, а это именно то различие, которое нужно более позднему рецензенту при оспаривании ряда.

Наконец, держите честной гранулярность наблюдения. Страница может отрисовать вид месяца, где только часть дат несёт ячейки, и снимок, записавший весь месяц как наблюдённый, заявил лишнее. Записывайте, какие даты действительно присутствовали в ответе, даже когда ответ это «ответ перечислил три из тридцати одной даты», а эти даты записывайте как absent_in_window, а не как закрытые.

Запись запроса вместе с наблюдением

Запись снимка доступности должна нести запрос, потому что без него страницу нельзя истолковать. Поля ниже это минимум, делающий два снимка сравнимыми.

ПолеСодержимоеЗачем оно в записи
canonical_queryНормализованный запрос из предыдущего шагаОпределяет, какой календарь запрошен
property_refИдентификатор объекта, привязанный к источникуОтделяет два объекта с похожими названиями
date_keyДата ночи в ISOОдна строка на ночь
room_codeТип номера, как его называет источникОтделяет люкс от стандартного номера
rate_codeТарифный план, как его называет источникОтделяет гибкий тариф от предоплаченного
stateОдно из пяти состоянийНе даёт прочитать отсутствие как закрытие
observed_atВремя снимка в UTCУпорядочивает наблюдения и ограничивает прогон
settle_msВремя до устойчивого состояния страницы, если измереноОтличает медленную страницу от отсутствующей

Два поля заслуживают пояснения. property_ref должен быть идентификатором, привязанным к источнику, а не названием, потому что два объекта в одном городе могут делить название, а сеть может переименовать один из них. settle_ms необязателен, но полезен: снимок, записавший состояние через 40 миллисекунд, вероятно прочитал скелет, а не календарь, и это стоит знать до того, как доверять строке.

Модель тарифного снимка применяет ту же дисциплину к одному тарифу, а не к календарю: четыре входа записываются на каждый снимок, потому что сравнение без них измеряет окружение. Доступности нужно это плюс ключ даты, потому что проживание охватывает несколько строк, каждая из которых может меняться независимо.

Граница условий

Страница бронирования находится за платформой, чьи условия решают, что можно собирать. Это не техническое ограничение, которое снимет лучшая настройка браузера; это условие, при котором данные вообще можно использовать. Там, где есть официальный партнёрский фид, партнёрский интерфейс или лицензированный канал распространения, он даёт ту же доступность с определённой схемой и заявленным правом использования.

RFC 9110 определяет семантику HTTP, включая кэширование и заголовок Vary, который сообщает кэшу, какие поля запроса повлияли на представление. Это механизм, которым страница говорит, что её содержимое зависит от большего, чем путь, и полезное напоминание о том, что ответ о доступности согласуется, а не фиксирован. Он ничего не говорит о том, разрешает ли конкретный сайт сбор, и никакой заголовок не отменяет вопрос условий.

Модель объявлений о недвижимости проводит ту же линию для данных об объектах: вхождение объявления, физический объект и предложение различны, а отсутствующая карточка не означает продажу. У доступности та же форма, но с диапазоном дат вместо объекта, и то же правило: наблюдение не является выводом.

Отсюда два практических ограничения. Первое: наблюдение не бронирование. Загрузить календарь и записать, что он показал, это иное действие, чем удержать номер, и второе полностью вне области. Второе: различие между двумя снимками это наблюдение, а не доказательство нарушения политики платформой. Такие выводы принадлежат тому, у кого есть инвентарь и соглашение.

Вопросы и ответы

Является ли проживание на три ночи одним значением доступности?

Нет. Это три строки дат, и каждая может нести своё состояние. Страница, суммирующая проживание, показывает проекцию, поэтому сводку нужно разложить до сравнения по ночам.

Означает ли отсутствующая ячейка, что номер недоступен?

Нет. Либо окно не покрывало дату (not_in_window), либо покрывало, а ответ не перечислил ячейку (absent_in_window), либо ответ не был принят (unaccepted). Держите все три отдельно от observed_closed, чтобы ни одно не читалось как закрытие.

Входят ли тип номера и тариф в ключ?

Входят вместе с датой, потому что распроданный люкс не закрывает отель, а закрытый тариф не закрывает номер. Сворачивание их в одно значение уровня страницы сливает наблюдения, которые должны оставаться раздельными.

Предоставляет ли BotBrowser данные доступности или бронирует номера?

Нет. Он предоставляет документированные входные данные браузера, включая географически согласованный выход и значения локали из профиля, чтобы сравнение могло объявить свой регион. Он не поставляет доступность, не держит инвентарь, не бронирует номер и не гарантирует результат.

Источники

Практический вывод

Моделируйте доступность как календарь с ключом по дате, где номер, тариф и размещение это измерения, и считайте дату выезда исключённой. Нормализуйте запрос до загрузки страницы и записывайте его в каждый снимок, потому что страница это проекция этого запроса, а не самостоятельный документ. Держите пять состояний на ячейку, чтобы отсутствие и неудачное наблюдение никогда не становились закрытиями. Там, где есть официальный партнёрский фид, используйте его, и пусть условия платформы решают, что может собирать браузерный прогон.

#Доступность Отелей#Данные Доступности#Автоматизация Браузера

Эта статья входит в руководство: Обзор настройки прокси: карта сетевых решений браузера

Выполните ту же проверку в BotBrowser

Загрузите профиль, сохраните внутри браузера те сигналы, о которых только что прочитали, и подтвердите результат на своей машине до раскатки.