user5378220
user5378220

Reputation:

Selenium click does not trigger event on website (python)

Sometimes when I'm using selenium to click on a particular link on a page, the click goes through but the website does not respond to the click. For example, here is the situation when I try to navigate between dates on the statistics page on nba.com.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec

import datetime
import time

def go_to_next_day(driver, next_date):
    for elem in driver.find_elements_by_css_selector('.date-selector i'):
        if 'right' in elem.get_attribute('class'):
            print 'Found next day!'
            elem.click()
            break
    else:
        raise ValueError('Unable to navigate to the next day')

    # wait 30 seconds until the next day loads
    WebDriverWait(driver, 30).until(
        ec.text_to_be_present_in_element((By.CSS_SELECTOR, '.date-selector > span'), next_date.strftime('%m/%d/%Y'))
    )


if __name__ == '__main__':
    # go to nba.com
    driver = webdriver.Firefox()
    driver.set_window_size(2560, 1600)
    driver.get('http://stats.nba.com/scores/#!/10/03/2014')

    print 'NBA.com loaded. Clicking to next day!!!'
    end_date = datetime.datetime.now()
    current_date = datetime.datetime.strptime('2014-10-03', '%Y-%m-%d')

    # after page loads, just click right until you get to current date
    while current_date <= end_date:
        # do something interesting on the page, modeled as a sleep
        time.sleep(1)

        next_date = current_date + datetime.timedelta(days=1)
        go_to_next_day(driver, next_date)
        current_date = next_date
        print 'Went to day {}'.format(current_date)

    driver.quit()
    print 'Done'

Why is it that the script always clicks, but the website only changes its page sometimes? Is it something to do with angular? I doubt it has anything to do with the OS, but I'm on a Mac OS X.

I'm not sure and would really like to figure out how to avoid the click failing, especially because I think I click and wait in the selenium way.

Upvotes: 4

Views: 1880

Answers (1)

alecxe
alecxe

Reputation: 473763

The problem is that the click does not make it go to the next day if the current day's data is still loading. In other words, if the "loading spinner" is visible - clicking the > button has no effect.

To solve it: wait for invisibility of the div.loader element containing the spinner:

def go_to_next_day(driver, next_date):
    wait = WebDriverWait(driver, 10)
    actions = ActionChains(driver)
    try:
        next_button = wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, '.date-selector i[class*=right]')))
        actions.move_to_element(next_button).click().perform()
    except TimeoutException:
        raise ValueError('Unable to navigate to the next day')

    # THIS IS THE KEY FIX
    wait.until(ec.invisibility_of_element_located((By.CSS_SELECTOR, "div.loader")))

    # wait until the next day loads
    wait.until(
        ec.text_to_be_present_in_element((By.CSS_SELECTOR, '.date-selector > span'), next_date.strftime('%m/%d/%Y'))
    )

I'm also operating with the next button a bit differently, feel free to continue with your own approach or switch to mine - the key fix is in the waiting for "spinner" invisibility. Works for me.

Upvotes: 3

Related Questions