Web Scraping Booking.Com
Booking.com, with over 28 million listings, is one of the largest websites for finding a place to stay while traveling. If you are opening a new hotel in any area, you might want to keep an eye on competitors and get notifications about new properties. All of this can be automated using web scraping! In this article, you will learn how to use Python and Selenium to extract data from the Booking.com search results page and handle pagination.
Setting Up the Prerequisites
This guide uses Python 3.10, but it should work with most Python versions. Start by creating a new directory to store all project files, then create a new Python file for the code itself:
$ mkdir booking_scraper
$ cd booking_scraper
$ touch app.py
You will need to install several different libraries:
- selenium
- selenium-wire
- webdriver-manager
You can install both libraries with this command:
$ pip install selenium selenium-wire webdriver-manager
Selenium will provide all the APIs for programmatic access to the browser, and Selenium Wire adds additional capabilities on top. We will discuss these extra capabilities later when we use them. The webdriver-manager helps you easily install the browser driver binary without having to manually download and link it in the code.

Getting the Booking.com Search Results Page
Let's try to get the search results page using Selenium to make sure everything is set up correctly. Save the following code in 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)
Note: This URL does not contain check-in and check-out dates, so if you want information about properties available on specific dates, select those dates in the search form and copy the resulting URL.
Executing this code will open a Chrome window and navigate to the property search page for San Francisco. Opening the browser window may take a minute because the Chrome driver binary may need to be downloaded.
The code itself is quite simple. It starts by importing the webdriver, service, and ChromeDriverManager. Usually, to initialize the webdriver, you need to provide it with the executable_path to the driver binary for the specific browser:
browser = webdriver.Chrome(executable_path=r "C:\\path\\to\\chromedriver.exe")
The biggest drawback of this approach is that every time the browser is updated, you need to download the updated browser driver binary. This quickly becomes tedious, so the webdriver_manager library simplifies the task by allowing you to pass ChromeDriverManager().install(). It will automatically download the needed binary and return the corresponding path, so you no longer have to worry about it.
The last line of code tells the driver to navigate to the search results page.
How to Extract Property Information from the Search Results Page
Before extracting any data, you need to decide what data to extract. In this guide, you will learn how to extract the following data from the search results page:
- Name
- Location
- Rating
- Number of reviews
- Thumbnail
- Price
To access DOM elements and extract data, you will use the default methods (find_element + find_elements) provided by Selenium. Additionally, CSS selectors and XPath will be used to find DOM elements. Which method you use will depend on the DOM structure and which method is most appropriate.
Extracting the Property Name and Link
Property title in 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')
Extracting the Property Address and Price
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
Extracting the Property Rating and Review Count
>>> print(property_cards[0].find_element(By.CSS_SELECTOR, '[data-testid="review-score"]').text)7.8Good491 reviews
for property in property_cards:# ...review_score, _, review_count = property.find_element(By.CSS_SELECTOR, '[data-testid="review-score"]').text.split('\n')
Extracting the Property Thumbnail
for property in property_cards:# ...image = property.find_element(By.CSS_SELECTOR, '[data-testid="image"]').
Navigating to the Next Page of Results
next_page_btn = driver.find_element(By.XPATH, '//button[contains(@aria-label, "Next page")]')
next_page_btn.click()
Now comes the tricky part. By default, Selenium does not provide a way to check if a specific background request has returned. This becomes a serious limitation when dealing with JS-heavy websites. Without such capability, there is no direct way to determine if the DOM has been updated with new results after clicking the next page button. You can compare the list of new properties with those already scanned, which gives you some indication of whether the DOM has been updated with new data. However, there is a simpler method.
This is where Selenium Wire shines. If you followed the installation instructions at the beginning of the article, you already have it installed. Selenium Wire allows you to inspect individual requests and find out whether the response returned successfully. Fortunately, it is a drop-in replacement for Selenium and does not require any code changes. Just update the imp


