Reputation:
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
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