Search code examples
seleniumselenium-webdriverdatepickerscrapyscreen-scraping

Screen scraping a Datepicker with Scrapy and Selenium on mouse hover


So I need to scrap a page like this for example and I am using Scrapy + Seleninum to interact with a date-picker calendar.

I realized that if a certain date is available a price shows on the tooltip, and if its not available if you hover on it nothing happens.

Whats the code for me to get the price that appears dynamically when you hover on an available day and also how do I know if its available or not just with the hover?


Solution

  • It is not that straightforward how to approach the problem because of the dynamic nature of the page - you have to use waits here and there and it's tricky to catch the HTML of the dynamic components appearing on click or hover.

    Here is the complete working code that would navigate to the page, click the "Check In" input, wait for the calendar to load and report the availability for each of the days in the calendar (it uses the presence of ui-datepicker-unselectable class to determine that). Then, it hovers each cell using the move_to_element() browser action, waits for the tooltip and gets the price:

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    
    driver = webdriver.Firefox()
    driver.get("https://www.airbnb.pt/rooms/265820?check_in=2016-04-26&guests=1&check_out=2016-04-29")
    
    # wait for the check in input to load
    wait = WebDriverWait(driver, 10)
    elem = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.book-it-panel input[name=checkin]")))
    elem.click()
    
    # wait for datepicker to load
    wait.until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, '.ui-datepicker:not(.loading)'))
    )
    
    days = driver.find_elements_by_css_selector(".ui-datepicker table.ui-datepicker-calendar tr td")
    for cell in days:
        day = cell.text.strip()
        if not day:
            continue
    
        if "ui-datepicker-unselectable" in cell.get_attribute("class"):
            status = "Unavailable"
        else:
            status = "Available"
    
        price = "n/a"
        if status == "Available":
            # hover the cell and wait for the tooltip
            ActionChains(driver).move_to_element(cell).perform()
            price = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.datepicker-tooltip'))).text
    
        print(day, status, price)
    

    Prints:

    1 Unavailable n/a
    2 Unavailable n/a
    3 Unavailable n/a
    4 Unavailable n/a
    5 Unavailable n/a
    6 Unavailable n/a
    7 Unavailable n/a
    8 Unavailable n/a
    9 Unavailable n/a
    10 Unavailable n/a
    11 Unavailable n/a
    12 Unavailable n/a
    13 Available €40
    14 Unavailable n/a
    15 Unavailable n/a
    16 Unavailable n/a
    17 Unavailable n/a
    18 Unavailable n/a
    19 Available €36
    20 Available €49
    21 Unavailable n/a
    22 Available €49
    23 Unavailable n/a
    24 Unavailable n/a
    25 Available €40
    26 Available €39
    27 Available €35
    28 Available €37
    29 Available €37
    30 Available €37