1

I have the following MRE code that is mean to select EU Odds from a dropdown:

from pathlib import Path
from time import sleep

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

chrome_driver = str(Path("chromedriver/chromedriver/"))
driver = webdriver.Chrome(chrome_driver)
driver.get("https://www.oddsportal.com/matches/tennis/")
driver.find_element(By.ID, "user-header-oddsformat-expander").click()
sleep(1)
wait = WebDriverWait(driver, 10)
target = "EU Odds"
wait.until(ec.element_to_be_clickable((By.XPATH, "//li[.='" + target + "']"))).click()

Everything works up until the final line which doesn't make the selection. If I try to do this manually on the page that chromedriver opens then I'm also unable to make the selection. However, if I open up a normal browsing window then I am able to make the selection.

Where am I going wrong?

Jossy
  • 589
  • 2
  • 12
  • 36
  • 1
    Even if I open the site manually, I can’t make a new selection or some selection other than `EU Odds`. It always reloads the page with the same option. Are you sure there is nothing wrong with the website itself? – Jarvis Dec 28 '20 at 16:17
  • @Jarvis - hey. I think you've figured out the issue indirectly. It looks like they've changed the site so you can only change the odds if you're logged in... – Jossy Dec 28 '20 at 16:25
  • I see, guess I should have posted this as my answer :D – Jarvis Dec 28 '20 at 16:26

4 Answers4

2

The actual issue is with the website itself. Trying to select any other option other than EU Odds doesn’t work even manually. Seems like you need to be logged in to do that.

Jarvis
  • 8,494
  • 3
  • 27
  • 58
  • 1
    I think it’s doing some IP-based filtering and setting up a country based on location. Try with VPN for EU country while running script and that dropdown will default to `EU Odds`-not the perfect solution but workaround – MikeCode Dec 28 '20 at 17:29
1

From a broader perspective there is nothing wrong in your code.

However to optimize your code you may like to:

  • Induce WebDriverWait for the element_to_be_clickable() for the expander to be clickable.

  • The texts EU Odds, UK Odds, US Odds, etc are not exactly within the <li> but within it's grand parent //li/a/span

  • So to select EU Odds, UK Odds, US Odds one by one your optimized Locator Strategies can be:

    driver.get('https://www.oddsportal.com/matches/tennis/')
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "EU Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    time.sleep(3) # for visual demonstration
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "UK Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    time.sleep(3) # for visual demonstration
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "user-header-oddsformat-expander"))).click()
    target = "US Odds"
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li/a/span[text()='" + target + "']"))).click()
    

This usecase

However even sucessfully clicking on the options with text as EU Odds, UK Odds, US Odds doesn't changes the DOM Tree. Now if you look into the HTML DOM the expander class itself is having the value as user-header-fakeselect-options. Additionally, the onclick attribute of the //li/a/span items are having return false;.

fakeselect

As per the discussion What's the effect of adding 'return false' to a click event listener? return false; does three separate things when called:

  • Calls event.preventDefault();
  • Calls event.stopPropagation();
  • Stops callback execution and returns immediately when called.

Hence selecting either of the dropdown options doesn't fires the onclick event and the HTML DOM remains unchanged.


Conclusion

Possibly the DOM would change as per the onclick events when a authenticated user performs the selection after loggind in within the website.

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
0

Try this. Selenium has a special way to handle dropdown selection

First import select :

from selenium.webdriver.support.ui import Select

Then assign the dropdown to a variable:

dropdown_element = browser.find_element_by_xpath('//*[@id="exam_id"]')

Then create an object:

dropdown_object = Select(dropdown_element)

Finally select the option:(there will be a value for every options)

dropdown_object.select_by_value('17')
cozmoguy
  • 1
  • 1
  • Thanks for trying to help out! I'm not sure what element I should be searching for in this line; `browser.find_element_by_xpath()`. I've tried `'//*[@id="user-header-oddsformat-expander"]'` which was what I clicked on before but I get the following error: `Select only works on ` element in the HTML for the dropdown? – Jossy Dec 26 '20 at 12:25
  • Can you add a screenshot of the website to your question and highlight the dropdown – cozmoguy Dec 27 '20 at 05:49
  • Hi. The website address is `https://www.oddsportal.com/matches/tennis/` – Jossy Dec 27 '20 at 10:37
  • Just to add to this. Selenium clicks on the dropdown successfully using this line: `driver.find_element(By.ID, "user-header-oddsformat-expander").click()` – Jossy Dec 28 '20 at 16:02
0

There are two issues with the xpatי: Too many apostrophes around the text Trying to locate the wrong tag, the clickable element is the <a> tag, not the <li> tag.

Use "//a[.=' + target + ']"

Guy
  • 46,488
  • 10
  • 44
  • 88