Веб-парсинг Booking.Com
Booking.com, насчитывающий более 28 млн. объявлений, является одним из крупнейших сайтов для поиска места для проживания во время путешествия. Если вы открываете новый отель в каком-либо районе, вам, возможно, захочется следить за конкурентами и получать уведомления об открытии новых объектов. Все это можно автоматизировать с помощью веб-парсинга! В этой статье вы узнаете, как с помощью Python и Selenium получить данные со страницы результатов поиска Booking.com, а также разобраться с пагинацией.
Настройка необходимых условий
В данном руководстве используется Python 3.10, но он должен работать с большинством версий Python. Начните с создания нового каталога, в котором будут храниться все файлы проекта, а затем создайте в нем новый Python-файл для самого кода:
$ mkdir booking_scraper
$ cd booking_scraper
$ touch app.py
Для дальнейшей работы вам потребуется установить несколько различных библиотек:
- selenium
- selenium-wire
- webdriver-manager
Вы можете установить обе эти библиотеки с помощью этой команды:
$ pip install selenium selenium-wire webdriver-manager
Selenium предоставит вам все API для программного доступа к браузеру, а Selenium Wire обеспечит дополнительные возможности поверх него. Эти дополнительные возможности мы обсудим позже, когда будем их использовать. Менеджер webdriver-manager поможет вам легко установить бинарный драйвер браузера без необходимости вручную загружать и размещать ссылки на него в коде.

Получение страницы результатов поиска Booking.com
Попробуем получить страницу результатов поиска с помощью Selenium, чтобы убедиться, что все настроено правильно. Сохраните следующий код в файле app.py:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManagerdriver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
url = "https://www.booking.com/searchresults.en-gb.html?ss=San+Francisco%2C+California%2C+United+States"
driver.get(url)
Примечание: Данный URL-адрес не содержит информации о датах заезда и выезда, поэтому если вы хотите получить информацию об объектах недвижимости, доступных в определенные даты, выберите эти даты в форме поиска и скопируйте полученный URL-адрес.
Выполнение этого кода приведет к открытию окна Chrome и переходу на страницу поиска недвижимости в Сан-Франциско. Открытие окна браузера может занять минуту, так как может потребоваться загрузка двоичного файла драйвера Chrome.
Сам код достаточно прост. Он начинается с импорта веб-драйвера, сервиса и менеджера ChromeDriverManager. Обычно для инициализации веб-драйвера необходимо указать ему исполняемый_путь к используемому двоичному файлу драйвера для конкретного браузера:
browser = webdriver.Chrome(executable_path=r "C:\\path\\to\\chromedriver.exe")
Самым большим недостатком этого способа является то, что каждый раз, когда браузер обновляется, необходимо загружать обновленный двоичный файл драйвера для браузера. Это быстро надоедает, поэтому библиотека webdriver_manager упрощает задачу, позволяя передавать команду ChromeDriverManager().install(). Она автоматически загрузит нужный двоичный файл и вернет соответствующий путь, так что вам больше не придется об этом беспокоиться.
Последняя строка кода просит драйвер перейти на страницу с результатами поиска.
Как извлечь информацию о свойствах из страницы результатов поиска
Прежде чем извлекать какие-либо данные, необходимо решить, какие данные вообще нужно извлекать. В этом руководстве вы узнаете, как извлечь из страницы результатов поиска следующие данные:
- Название
- Населенный пункт
- Рейтинг
- Количество отзывов
- Эскиз
- Цена
Для доступа к элементам DOM и извлечения из них данных вы будете использовать методы по умолчанию (find_element + find_elements), предоставляемые Selenium. Кроме того, для поиска элементов DOM будут использоваться селекторы CSS и XPath. То, какой именно метод вы используете для поиска элемента, будет зависеть от структуры DOM и от того, какой метод является наиболее подходящим.
Извлечение имени свойства и ссылки
Property title devtools
property_cards = driver.find_elements(By.CSS_SELECTOR, 'div[data-testid="property-card"]')
for property in property_cards:name = property.find_element(By.CSS_SELECTOR,'div[data-testid="title"]').textlink = property.find_element(By.CSS_SELECTOR,'a[data-testid="title-link"]').get_attribute('href')
Извлечение адреса и цены объекта недвижимости
for property in property_cards:# ...address = property.find_element(By.CSS_SELECTOR, '[data-testid="address"]').text
for property in property_cards:price = property.find_element(By.CSS_SELECTOR, '[data-testid="price-and-discounted-price"]').text
Извлечение рейтинга объекта и количества отзывов
>>> print(property_cards[0].find_element(By.CSS_SELECTOR, '[data-testid="review-score"]').text)7.8Хорошо491 отзыв
for property in property_cards:# ...review_score, _, review_count = property.find_element(By.CSS_SELECTOR, '[data-testid="review-score"]').text.split('\\n')
Извлечение миниатюры свойства
for property in property_cards:# ...image = property.find_element(By.CSS_SELECTOR, '[data-testid="image"]').
Переход к следующей странице результатов
next_page_btn = driver.find_element(By.XPATH, '\/\/button[contains(@aria-label, "Следующая страница")]')
next_page_btn.click()
Теперь начинается самая сложная часть. Selenium по умолчанию не предоставляет возможности проверить, вернулся ли конкретный фоновый запрос. Это становится серьезным ограничением при работе с сайтами, перегруженными JS. Без такой возможности нет прямого способа выяснить, обновлялся ли DOM новыми результатами после нажатия кнопки следующей страницы. Вы можете сравнить список новых свойств с уже отсканированными, и это даст вам некоторое представление о том, обновлялась ли DOM новыми данными. Однако есть и более простой способ.
Именно здесь и проявляет себя Selenium Wire. Если вы следовали инструкциям по установке, приведенным в начале статьи, то он у вас уже установлен. Selenium Wire позволяет проверять отдельные запросы и выяснять, успешно ли вернулся ответ. К счастью, он является полноценной заменой Selenium и не требует изменения кода. Просто обновите имп


