Python Selenium + Datepicker Click

10,845

One tricky thing about this calendar is that you first need to hover a particular day and then relocate the active day and click it. Here is a working implementation that selects the first available start and end dates and prints the calculated 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.maximize_window()

wait = WebDriverWait(driver, 10)

url = 'https://www.homeaway.pt/arrendamento-ferias/p1418427a?uni_id=1590648'
driver.get(url)

# pick start date
start_date = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".quotebar-container input[name=startDateInput]")))
start_date.click()

first_available_date = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#ui-datepicker-div td.full-changeover > a")))
ActionChains(driver).move_to_element(first_available_date).perform()
driver.find_element_by_css_selector("#ui-datepicker-div td.full-selected.full-changeover > a").click()

# pick end date (TODO: violates DRY principle, refactor!)
end_date = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".quotebar-container input[name=endDateInput]")))
end_date.click()

first_available_date = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#ui-datepicker-div td.full-changeover > a")))
ActionChains(driver).move_to_element(first_available_date).perform()
driver.find_element_by_css_selector("#ui-datepicker-div td.full-selected.full-changeover > a").click()

# get the calculated price
price = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".price-quote .price-total")))
print(price.text)

driver.close()

At the moment, it selects 20/04/2016 and 23/04/2016 and prints 180€.

Hope that helps.

Share:
10,845
psychok7
Author by

psychok7

Software Engineer

Updated on June 26, 2022

Comments

  • psychok7
    psychok7 almost 2 years

    I have been banging my head around trying to get the price of a room like this for example by clicking the first available (green) datepicker checkin input and then clicking the first available datepicker checkout input so the price for the minium period is generated.

    My code is a mess so i would really appreciate if someone could post a cleaner code to achieve that.

    I am using Python selenium + scrapy although something in Java for example would still help.

    UPDATE:

    here is the code:

    def availability(self, doc):
        url = doc['url'] + '#calendar'
        self.driver.get(url)
        is_active = True
        # We want to the availability/price for each day in a month.
        availabilities = []
    
        # wait for the check in input to load
        wait = WebDriverWait(self.driver, 10)
    
        try:
            elem = wait.until(
                EC.visibility_of_element_located(
                    (By.CSS_SELECTOR, ".dates-group input[name=startDateInput]")
                )
            )
        except TimeoutException:
            pass
        else:
            elem.click()  # open calendar
            # wait for datepicker to load
            wait.until(
                EC.visibility_of_element_located(
                    (By.CSS_SELECTOR, '.ui-datepicker:not(.loading)'))
            )
            days = self.driver.find_elements_by_css_selector(
                "#ui-datepicker-div tr td"
            )
    
            for cell in days:
                day = cell.text.strip()
                if not day:
                    continue
    
                if "full-changeover" not in cell.get_attribute("class"):
                    available = False
                else:
                    available = True
    
                self.logger.warning('CELL "%s"', cell)
                self.logger.warning('DAY "%s"', day)
                self.logger.warning('available "%s"', available)
    
    
            # The first iteration was to list the availability, now we want to
            # click the first available element to get the price
            for cell in days:
                day = cell.text.strip()
                if not day:
                    continue
    
                if "full-changeover" in cell.get_attribute("class"):
                    self.logger.warning('CLICK IT "%s"', day)
                    self.driver.implicitly_wait(10)
                    x = self.driver.find_element_by_xpath("//table/tbody/tr/td/a[text()=" + day + "]")
                    self.driver.implicitly_wait(10)
                    x.click() # Element not found in the cache issue here
                    # import ipdb; ipdb.set_trace()
    
                # self.logger.warning('CELL "%s"', cell)
                # self.logger.warning('DAY "%s"', day)
                # self.logger.warning('available "%s"', available)
    
            # elem.click()  # close checkin calendar
    
            # Now lets click on the checkout input to get the price and minimum
            # number of days. We probably don't have to wait for the checkout
            # because its already loaded but you never know.
    
            try:
                elem = wait.until(
                    EC.visibility_of_element_located(
                        (By.CSS_SELECTOR,
                         ".dates-group input[name=endDateInput]")
                    )
                )
            except TimeoutException:
                pass
            else:
                # elem.click()  # open calendar in checkout input
                # wait for datepicker to load
                wait.until(
                    EC.visibility_of_element_located(
                        (By.CSS_SELECTOR, '.ui-datepicker:not(.loading)'))
                )
                days = self.driver.find_elements_by_css_selector(
                    "#ui-datepicker-div tr td"
                )
    
                for cell in days:
                    day = cell.text.strip()
                    if not day:
                        continue
    
                    # This is the first available date to checkout
                    if "full-changeover" in cell.get_attribute("class"):
                        self.logger.warning('CLICK IT "%s"', available)
                        import ipdb; ipdb.set_trace()
                        # Here we would get the generated price
    
    
    
                    self.logger.warning('CELL "%s"', cell)
                    self.logger.warning('DAY "%s"', day)
                    self.logger.warning('available "%s"', available)
    
    
    
    
            import ipdb; ipdb.set_trace()
    
        return {'availabilities': availabilities, 'is_active': is_active}
    

    Thanks

  • psychok7
    psychok7 about 8 years
    let me try this tonight and ill come mark it right after :)
  • psychok7
    psychok7 about 8 years
    it works :) .. thanks again for your help spent a whole afternoon trying to figure this out
  • psychok7
    psychok7 almost 8 years
    hi alecxe , with this solution how can i get the availability for the folowing months? i am trying to click on the calendar next button after the first start_date click with self.driver.find_element_by_css_selector('.ui-datepicker-nex‌​t.ui-corner-all').cl‌​ick() but i am getting a ElementNotVisibleException any ideas what i am doing wrong?
  • alecxe
    alecxe almost 8 years
    @psychok7 hey, would you be okay to create a separate question? More users would have a chance to help. I'll definitely take a look, throw me a link here. Thanks!
  • psychok7
    psychok7 almost 8 years
    here is the question stackoverflow.com/questions/37010064/… . I am having trouble with 2 different sites but the code is all there