Страницы объявлений Airbnb содержат именно те ценовые данные, которые нужны для туристических исследований, анализа рынка и мониторинга конкурентов: стоимость за ночь, название объявления, рейтинг гостей и публичное местоположение, указанное хозяином. Проблема в том, что Airbnb отображает эти страницы на стороне клиента и активно защищает их от автоматизированного трафика, поэтому обычный HTTP-запрос возвращает пустую оболочку без цены.
Это руководство показывает, как парсить цены Airbnb с помощью Python надёжным способом. Вы создадите небольшой рабочий скрапер, который получает отрисованную страницу объявления через Crawling API, извлекает нужные поля с помощью BeautifulSoup и выводит чистую структурированную запись. Руководство намеренно ограничено данными публичных объявлений, а правовой раздел в конце не является шаблонным текстом, поэтому прочитайте его, прежде чем применять скрапер к реальным объёмам.
Что вы создадите
Скрипт на Python, который принимает публичный URL объявления Airbnb, получает отрисованный HTML через Crawling API и извлекает структурированную запись для этого объявления. В качестве рабочего примера мы будем использовать URL отдельной комнаты и извлечём следующие поля:
- Название название объявления, отображаемое в верхней части страницы.
- Цена стоимость за ночь для запрошенных дат.
- Рейтинг публичный рейтинг гостей, например "4.92".
- Местоположение район, который Airbnb публично показывает для объявления.
Почему обычный запрос не работает на Airbnb
Если запросить URL комнаты Airbnb с помощью простого HTTP-клиента, вы получите ответ со статусом 200 и почти без данных объявления в теле. Против вас работают два фактора. Во-первых, Airbnb отрисовывает содержимое объявлений в браузере с помощью JavaScript, поэтому начальный HTML является оболочкой, которая заполняется только после выполнения скриптов страницы. Во-вторых, Airbnb быстро выявляет автоматизированный трафик: IP-адреса датацентров и паттерны запросов, которые не выглядят как настоящий браузер, блокируются до получения отрисованного содержимого.
Есть ещё одна особенность, специфичная для цен. После изменений в ценообразовании Airbnb стоимость за ночь отображается только после того, как на странице указаны даты заезда и выезда, а также количество гостей. Цены динамические: одно и то же объявление показывает разные цифры для разных дат, выходных и сезонов. Поэтому рабочий скрапер цен Airbnb требует браузера для отрисовки страницы, IP-адреса, который платформа воспринимает как реального посетителя, и параметров дат в URL, чтобы цена вообще отображалась.
Можно собрать это самостоятельно, используя headless-браузер и пул ротируемых резидентных прокси, но поддержание этой инфраструктуры занимает большую часть работы. Crawling API объединяет сложные части в один вызов: вы отправляете ему URL объявления с токеном JavaScript, он отрисовывает страницу за доверенным IP-адресом и возвращает готовый HTML для парсинга.
Crawlbase предлагает два типа токенов. Обычный токен получает статический HTML; токен JavaScript (JS) сначала отрисовывает страницу в настоящем браузере. Airbnb использует клиентский рендеринг, поэтому здесь нужен JS-токен. Использование обычного токена возвращает ту же пустую оболочку, что и обычный запрос, без цены для парсинга.
Предварительные требования
Перед написанием кода необходимо подготовить несколько вещей. Это не займёт много времени.
Базовые знания Python. Вы должны уметь писать и запускать скрипты Python, а также устанавливать пакеты с помощью pip. Если вы новичок в парсинге HTML, наше руководство по использованию BeautifulSoup в Python охватывает основы работы с селекторами, которые предполагаются в этом руководстве.
Python 3.8 или выше. Проверьте свою версию командой python --version. Если у вас её нет, установите с python.org или через дистрибутив, например Anaconda.
Аккаунт Crawlbase и JS-токен. Зарегистрируйтесь, откройте панель управления и скопируйте токен JavaScript (JS) со страницы документации аккаунта. Относитесь к токену как к паролю: он аутентифицирует ваши запросы, поэтому не включайте его в систему контроля версий.
Настройка проекта
Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, затем установите две библиотеки, необходимые скраперу.
python --version python -m venv airbnb_env source airbnb_env/bin/activate pip install crawlbase beautifulsoup4
В Windows активируйте окружение командой airbnb_env\Scripts\activate вместо строки source. Две зависимости выполняют основную работу: crawlbase является официальным клиентом для Crawling API, а beautifulsoup4 парсит возвращаемый HTML, позволяя извлекать отдельные поля по CSS-селектору.
Шаг 1: получение отрисованного объявления
Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его с JS-токеном и запросите URL объявления с указанными датами. Проверка кода статуса перед парсингом делает ошибки явными, а не скрытыми.
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["status_code"] == 200: return response["body"].decode("latin1") print(f"Request failed: {response['status_code']}") return None if __name__ == "__main__": page_url = ( "https://www.airbnb.com/rooms/721540609203378406" "?check_in=2026-07-09&check_out=2026-07-12&adults=2" ) html = crawl(page_url) print(html[:500] if html else "No HTML returned")
Параметры запроса check_in, check_out и adults обязательны для отображения цены. Без них страница отрисовывается, но стоимость за ночь остаётся скрытой, поэтому поле цены будет пустым независимо от качества вашего селектора. Два параметра ожидания важны для клиентски отрисовываемых сайтов: ajax_wait указывает API ждать завершения загрузки асинхронного контента, а page_wait удерживает фиксированное количество миллисекунд после загрузки, чтобы элементы с поздней отрисовкой появились до захвата страницы. Пять секунд является разумным начальным значением; увеличьте его, если цена возвращается пустой. Airbnb отправляет страницы в различных кодировках, поэтому декодирование с помощью latin1 позволяет избежать ошибок байтов, которые может вызвать строгое декодирование UTF-8. Запустите скрипт, и вы должны увидеть реальную разметку объявления, а не пустую оболочку, которую возвращает обычный запрос.
Airbnb требует отрисованной страницы за доверенным IP-адресом в одном вызове. Crawling API принимает JS-токен, запускает страницу в настоящем браузере, ротирует резидентные IP-адреса на стороне сервера и передаёт готовый HTML, поэтому вам не нужно самостоятельно запускать headless-флот и пул прокси. Начните с публичного объявления на бесплатном тарифе.
Шаг 2: парсинг полей объявления с помощью BeautifulSoup
Имея отрисованный HTML, загрузите его в BeautifulSoup и извлеките каждое поле по его селектору. Airbnb размещает основные детали в стабильных секционных контейнерах, поэтому можно сопоставить название, цену, рейтинг и местоположение с отдельными селекторами. Оберните всё извлечение в блок try/except, чтобы отсутствие одного поля не прерывало выполнение.
from bs4 import BeautifulSoup def text_of(soup, selector): el = soup.select_one(selector) return el.get_text(strip=True) if el else None def scrape_listing(html): soup = BeautifulSoup(html, "html.parser") return { "title": text_of(soup, 'div[data-section-id="TITLE_DEFAULT"] h1'), "price": text_of(soup, 'div[data-testid="book-it-default"] span > span'), "rating": text_of(soup, 'div[data-testid="pdp-reviews-highlight-banner-host-rating"] span'), "location": text_of(soup, 'div[data-section-id="LOCATION_DEFAULT"] h3'), }
Вспомогательная функция text_of делает сразу две полезные вещи: запрашивает один элемент и возвращает None при его отсутствии вместо того, чтобы выбрасывать исключение при вызове .get_text() на пустом объекте. Это делает извлечение устойчивым при отсутствии поля, что часто встречается, поскольку у новых объявлений может ещё не быть рейтинга. Атрибуты data-section-id и data-testid в Airbnb более стабильны, чем хешированные CSS-имена классов, поэтому везде, где возможно, отдавайте предпочтение этим атрибутам данных в качестве якорей.
Разметка Airbnb, особенно хешированные имена классов, меняется без предупреждения. Относитесь к приведённым выше селекторам как к начальному шаблону, а не к постоянному контракту. Когда поле возвращает None, повторно осмотрите живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов является нормой для любого производственного скрапера, а не признаком неисправности.
Шаг 3: объединение всего вместе
Теперь свяжите получение данных и парсинг в один рабочий скрипт. Получите отрисованный HTML, передайте его парсеру и выведите структурированную запись в формате JSON.
import json from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["status_code"] == 200: return response["body"].decode("latin1") print(f"Request failed: {response['status_code']}") return None def text_of(soup, selector): el = soup.select_one(selector) return el.get_text(strip=True) if el else None def scrape_listing(html): soup = BeautifulSoup(html, "html.parser") return { "title": text_of(soup, 'div[data-section-id="TITLE_DEFAULT"] h1'), "price": text_of(soup, 'div[data-testid="book-it-default"] span > span'), "rating": text_of(soup, 'div[data-testid="pdp-reviews-highlight-banner-host-rating"] span'), "location": text_of(soup, 'div[data-section-id="LOCATION_DEFAULT"] h3'), } def main(): page_url = ( "https://www.airbnb.com/rooms/721540609203378406" "?check_in=2026-07-09&check_out=2026-07-12&adults=2" ) html = crawl(page_url) if not html: return data = scrape_listing(html) print(json.dumps(data, indent=2)) if __name__ == "__main__": main()
Как выглядит вывод
Запустите полный скрипт командой python scraper.py, и вы получите чистую структурированную запись для объявления, готовую для записи в JSON, CSV или базу данных.
{ "title": "Lovely Studio with Burj Khalifa views from Balcony", "price": "$187 per night", "rating": "4.92", "location": "Dubai, United Arab Emirates" }
Парсинг цен для разных дат
Один диапазон дат подходит для демонстрации; интересная работа с ценами предполагает сравнение одного объявления для многих дат, поскольку цены Airbnb меняются в зависимости от календаря. Схема остаётся той же: ведите список пар дат, перестраивайте URL для каждой, получайте данные через Crawling API и парсите той же функцией. Поскольку структура объявления не меняется, уже написанный парсер работает для любой даты без изменений.
room_id = "721540609203378406" date_ranges = [ ("2026-07-09", "2026-07-12"), ("2026-08-13", "2026-08-16"), ] results = [] for check_in, check_out in date_ranges: url = ( f"https://www.airbnb.com/rooms/{room_id}" f"?check_in={check_in}&check_out={check_out}&adults=2" ) html = crawl(url) if html: row = scrape_listing(html) row["check_in"] = check_in results.append(row) with open("airbnb_prices.json", "w") as f: json.dump(results, f, indent=2)
Чтобы найти URL объявлений, можно получить публичные результаты поиска Airbnb по той же схеме, собрать ссылки на комнаты, а затем посещать каждую с указанием дат. Просто поддерживайте разумный объём и соблюдайте ожидания по частоте запросов, описанные ниже. Если вы планируете использовать эти данные в модели ценообразования, наше руководство по использованию веб-скрапинга для анализа цен рассказывает о том, как команды превращают поток тарифов в нечто, готовое для принятия решений.
Как оставаться незаблокированным
Даже при решённом вопросе с рендерингом Airbnb следит за трафиком, характерным для скраперов. Несколько привычек помогают поддерживать работоспособность, и они применимы к любому сложному JavaScript-зависимому целевому сайту.
- Соблюдайте темп запросов. Многократный запрос одного объявления для десятков диапазонов дат в тесном цикле является быстрейшим способом получить ограничение. Распределите запросы и варьируйте цели вместо обхода одного пути на полной скорости.
- Полагайтесь на ротацию. Пул резидентных IP-адресов распределяет запросы по множеству реальных адресов пользователей, чтобы ни один из них не превысил лимит. Crawling API обрабатывает это за вас; если вы используете собственный стек, это и есть та часть, которую нужно правильно реализовать.
- Читайте коды статусов. Прогон, который начинает возвращать запросы на проверку или ошибки, сигнализирует о том, что текущей частоты или уровня IP уже недостаточно. Воспринимайте это как сигнал к замедлению, а не как шум, который нужно игнорировать.
Для более широкого руководства смотрите как парсить сайты, не получая блокировку и более глубокое погружение в тему как обходить CAPTCHA при веб-скрапинге. Поскольку Airbnb очень сильно зависит от JavaScript, также стоит прочитать наше руководство по обходу JavaScript-сайтов. Если вы предпочитаете маршрутизировать собственный трафик через ротируемый пул вместо использования управляемого API, Smart AI Proxy предоставляет ту же ротацию резидентных IP-адресов в качестве обычного прокси-эндпоинта.
Законно ли парсить Airbnb?
Разрешённость парсинга Airbnb зависит от условий использования Airbnb, вашей юрисдикции и того, что вы делаете с данными. Условия использования Airbnb прямо ограничивают автоматизированный доступ, поэтому парсинг может противоречить этим условиям независимо от того, насколько осторожны ваши инструменты. Ни один из кодов здесь не изменяет этого; он просто обеспечивает работу технической части. Прочитайте Условия использования Airbnb и его файл robots.txt, и относитесь к обоим как к границам того, что вы собираете.
Несколько правил, которых стоит придерживаться. Собирайте только публичные данные объявлений: название, стоимость за ночь, публичный рейтинг и местоположение, которое Airbnb показывает в объявлении без учётной записи. Уважайте ожидания Airbnb по частоте запросов и поддерживайте объём запросов достаточно низким, чтобы не создавать нагрузку на серверы. Это руководство намеренно ограничено публичными страницами объявлений, поскольку именно это делает работу оправданной.
Не менее важно то, что не охвачено. Не собирайте персональные данные хозяев или гостей, контактную информацию или сообщения. Не трогайте страницы за логином, данные аккаунтов или бронирований, доступ к которым требует аутентификации, и всё, что требует обхода аутентификации. Это выходит за рамки данного руководства и противоречит условиям Airbnb. Для коммерческого или крупномасштабного использования правильным путём является официальное партнёрство или соглашение об API с Airbnb, а не более хитрый скрапер. Только публичные данные объявлений.
Ключевые выводы
- Airbnb использует клиентский рендеринг. Обычный запрос возвращает пустую оболочку, поэтому необходимо отрисовать страницу перед парсингом.
-
Для цен нужны даты. Передайте
check_in,check_outиadultsв URL, иначе стоимость за ночь никогда не отрисуется; цены динамические и меняются в зависимости от календаря. -
Нужны одновременно рендеринг и доверенный IP-адрес. Crawling API с JS-токеном делает обе вещи в одном вызове;
ajax_waitиpage_waitуправляют временем ожидания содержимого. -
BeautifulSoup выполняет извлечение. Используйте атрибуты
data-section-idиdata-testidдля получения названия, цены, рейтинга и местоположения, и ожидайте, что селекторы будут меняться. - Оставайтесь в рамках публичных данных. Соблюдайте ToS и robots.txt Airbnb, предпочитайте официальное партнёрство для коммерческого использования и никогда не трогайте персональные данные хозяев или гостей, сообщения или страницы за логином.
Часто задаваемые вопросы
Почему обычный запрос не возвращает цену с Airbnb?
Две причины. Во-первых, Airbnb отрисовывает содержимое объявлений на стороне клиента с помощью JavaScript, поэтому исходный HTML является оболочкой, которая заполняется только после выполнения скриптов страницы. Во-вторых, стоимость за ночь отрисовывается только тогда, когда URL содержит даты заезда и выезда, а также количество гостей. Простой HTTP-запрос без дат возвращает статус 200 и отсутствие цены. Отрисовка страницы с помощью JS-токена Crawling API с указанием дат в URL является тем, что заставляет цену появиться.
Нужен ли мне обычный токен или JS-токен для Airbnb?
JS-токен. Обычный токен получает статический HTML, который на Airbnb является той же пустой оболочкой, что возвращает обычный запрос. JS-токен отрисовывает страницу в настоящем браузере перед передачей HTML, поэтому поля объявления, включая цену, присутствуют при парсинге BeautifulSoup.
Почему одно и то же объявление показывает разные цены?
Airbnb использует динамическое ценообразование. Стоимость за ночь меняется в зависимости от запрошенных дат, выходных и будних дней, спроса и сезона, и некоторые хозяева применяют скидки за длительность пребывания. Это ожидаемо, а не ошибка в скрапере. Если вы хотите сравнивать цены, перебирайте несколько диапазонов дат для одной комнаты и фиксируйте тариф для каждого, как это делается в примере с несколькими датами в данном руководстве.
Мои селекторы возвращают None. Что изменилось?
Скорее всего, разметка Airbnb. Хешированные CSS-имена классов часто меняются, а макеты секций сдвигаются со временем, поэтому селекторы, которые работали в прошлом месяце, могут сломаться. Используйте более стабильные атрибуты data-section-id и data-testid там, где это возможно, повторно осмотрите живую страницу в инструментах разработчика браузера, когда поле возвращает пустое значение, и обновите селектор. Периодическое обслуживание селекторов является нормой для любого производственного скрапера.
Как не получить блокировку при парсинге Airbnb?
Поддерживайте низкую частоту запросов с одного IP-адреса, варьируйте цели вместо перебора одного объявления для множества дат подряд и маршрутизируйте через ротируемые резидентные IP-адреса, чтобы ни один адрес не превысил лимит. Crawling API управляет ротацией и доверенным пулом IP-адресов за вас; если вы строите собственный стек, это именно та часть, в которую стоит инвестировать. Следите за кодами статусов и замедляйтесь, когда начинаете видеть запросы на проверку.
Какие данные Airbnb можно законно собирать?
Ограничьтесь публичными данными объявлений: названием, стоимостью за ночь, публичным рейтингом и местоположением, отображаемым в объявлении без входа в систему. Не собирайте персональные данные хозяев или гостей, контактные данные, сообщения или что-либо за логином, и никогда не обходите аутентификацию. Соблюдайте условия использования и robots.txt Airbnb, а для коммерческого или массового использования добивайтесь официального партнёрства или соглашения об API, а не масштабируйте скрапер на публичном сайте.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
