DAVIDBALAS1
DAVIDBALAS1

Reputation: 484

selenium python clicking a href by text inside

I am trying to switch countries programmatically in this site for some automation testing, the prices are different in each country so I am programming a little tool to help me decide where to buy from.

First, I get all the currencies into a list by doing this:

def get_all_countries():
    one = WebDriverWait(driver1, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "selected-currency")))
    one.click()
    el = WebDriverWait(driver1, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, "site-selector-list")))
    list_return = []
    a_tags = el.find_elements_by_tag_name('a')
    for a in a_tags:
        list_return.append(a.text)
    return list_return

For example, it returns: ['United Kingdom', 'United States', 'France', 'Deutschland', 'España', 'Australia', 'Россия'] and then, I iterate through the list and each time calling this function:

def set_country(text):
    is_change_currency_displayed = driver1.find_element_by_id("siteSelectorList").is_displayed()
    if not is_change_currency_displayed:  # get_all_countries function leaves dropdown open. Check if it is open before clicking it.
        one = WebDriverWait(driver1, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "selected-currency")))
        one.click()
    div = WebDriverWait(driver1, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, "site-selector-list")))
    a_tags = div.find_elements_by_tag_name('a')
    for a in a_tags:
        try:
            if a.text == text:
                driver1.get(a.get_attribute("href"))
        except StaleElementReferenceException:
            set_country(text)

When comparing a.text to text, I got a StaleElementReferenceException, I read online that it means the object is changed from when I saved it, and a simple solution is to call the function again. However, I don't like this solution and this code a lot, I think it is not effective and takes too much time, any ideas?

EDIT:

def main(url):
    driver1.get(url)
    to_return_string = ''
    one = WebDriverWait(driver1, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "selected-currency")))
    one.click()
    el = WebDriverWait(driver1, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, "site-selector-list")))
    a_tags = el.find_elements_by_tag_name('a')
    for a in a_tags:
        atext = a.text
        ahref = a.get_attribute('href')
        try:
            is_change_currency_displayed = driver1.find_element_by_id("siteSelectorList").is_displayed()
            if not is_change_currency_displayed:  # get_all_countries function leaves dropdown open.
                one = WebDriverWait(driver1, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "selected-currency")))
                one.click()
            driver1.get(ahref)
            current_price = WebDriverWait(driver1, 10).until(
                EC.visibility_of_element_located((By.CSS_SELECTOR, ".current-price")))
            to_return_string += ("In " + atext + " : " + current_price.text + ' \n')
            print("In", atext, ":", current_price.text)
        except TimeoutException:
            print("In", atext, ":", "Timed out waiting for page to load")
            to_return_string += ("In " + atext + " : " + " Timed out waiting for page to load" + ' \n')
    return to_return_string


main('http://us.asos.com/asos//prd/7011279')

Upvotes: 3

Views: 298

Answers (2)

Naveen Kumar R B
Naveen Kumar R B

Reputation: 6398

If I understand the problem statement correctly, Adding break statement solves the problem:

def set_country(text):
    is_change_currency_displayed = driver1.find_element_by_id("siteSelectorList").is_displayed()
    if not is_change_currency_displayed:  # get_all_countries function leaves dropdown open. Check if it is open before clicking it.
        one = WebDriverWait(driver1, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "selected-currency")))
        one.click()
    div = WebDriverWait(driver1, 10).until(EC.visibility_of_element_located((By.CLASS_NAME, "site-selector-list")))
    a_tags = div.find_elements_by_tag_name('a')
    for a in a_tags:
        try:
            if a.text == text:
                driver1.get(a.get_attribute("href"))
                break
        except StaleElementReferenceException:
            set_country(text)

DOM is updated once driver.get is called. so, the references related to old page (i.e., a_tags) won't work.

Instead, you should break the loop and come out as soon as the given country page is retrieved using driver.get once the condition is satisfied. So, you set the country you want and no need to iterate over and over again to check if condition, which obviously results in StaleElementReferenceException.

Upvotes: 2

Moshisho
Moshisho

Reputation: 2981

If your stale element is the a tag and not the div, you can iterate over the a tags length and get each element's text through the div:

for i in range(len(div.find_elements_by_tag_name('a')):
    if div.find_elements_by_tag_name('a')[i].text == text:
        driver1.get(div.find_elements_by_tag_name('a')[i].get_attribute("href"))

That way you can the most recent element from the DOM.

If your stale element is the div then you'll need to verify that the drop down isn't disappearing after your one.click() with hovering it or some other way.

Another approach would be to change your a.text to have a wait:

wait = WebDriverWait(driver, 10, poll_frequency=1, ignored_exceptions=[StaleElementReferenceException])
a = wait.until(EC.text_to_be_present_in_element((By.YourBy)))

Upvotes: 0

Related Questions