Python Selenium – why the button is not being clicked
Question:
Please refer to the following webpage: https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls
I have two functions to click on either the Chicago bulls or Miami Heat as seen on the webpage from the link above. Why is my current code no longer clicking on either? I need to be able to use the team variable as the names will constantly change.
Main:
driver = startup_login('https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls')
team = "Chicago"
proline_go_to_match2(driver,team)
Functions:
def proline_go_to_match2(driver, team):
#print(team)
try:
match = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li[1]//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]")) )
match.click()
except:
driver.quit()
def proline_go_to_match3(driver, team):
#print(team)
try:
match = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li[2]//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]")) )
match.click()
except:
driver.quit()
Answers:
for your xpath, it can find two elements, you can try the following code, it can work well, opening browser will implicit to wait for page ready.
from clicknium import clicknium as cc
if not cc.chrome.extension.is_installed():
cc.chrome.extension.install_or_update()
def get_elements(tab,team):
xpath = "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]"
return tab.find_elements_by_xpath(xpath)
tab = cc.chrome.open("https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls")
elements = get_elements(tab, "Chicago")
for elem in elements:
elem.click()
elements = get_elements(tab, "Miami")
for elem in elements:
elem.click()
You have to add some wait time in the function and you don’t need to use 2 functions to do click operations on 2 different team names, you can use just one, like below:
def proline_go_to_match(driver, team):
try:
time.sleep(4)
match = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH,"(.//span[@class='fdjgs-outcome-wrapper' and @title=contains(.,'" + team + "')])[1]")))
match.click()
except:
driver.quit()
Always, try to use simplified Xpath.
You can pass any value to the argument – ‘team’ like "Chicago" or "Miami".
Check for consent and click on that if exists.
use python format() function to change the parameter.
Use js executor to click else will get element intercepted error you can use actionchain as well.
driver.get("https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls")
wait=WebDriverWait(driver,20)
#check for consent
try:
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Continue']"))).click()
except:
pass
team="Chicago"
items=wait.until(EC.visibility_of_all_elements_located((By.XPATH, "//span[contains(@aria-label, '{0}')]//span[starts-with(., '{0}')]".format(team))))
for item in items:
driver.execute_script("arguments[0].click();", item)
print("Button clicked")
Three things that could help: (1) Using equivalent JavaScript
rather than the Selenium
click method; (2) using an explicit wait in finding the element you want to be clicked; and (3) injecting driver options that make you appear more like a legitimate user, less like a bot.
(1) Executing JS to click
Don’t use the Selenium
click method:
some_element_name.click()
Do this instead:
driver.execute_script("arguments[0].click();", some_element_name)
(2) Add waits
We want to give the page time to render first. We could use, say, time.sleep(n)
but it’s significantly better to do an explicit wait, that waits until <condition>
. So, don’t do this:
click_target = driver.find_element(By.<method>, '<tag>')
Do this instead:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 15)
click_target = wait.until(EC.presence_of_element_located((By.<method>, '<tag>')))
(3) Optimizing driver options for covertness
Keep it discreet that we’re a bot.
from selenium.webdriver.chrome.options import Options # chrome example
options = Options()
options.add_argument("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36") # legit looking user agent
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument("disable-infobars")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options) # then init with options
Please refer to the following webpage: https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls
I have two functions to click on either the Chicago bulls or Miami Heat as seen on the webpage from the link above. Why is my current code no longer clicking on either? I need to be able to use the team variable as the names will constantly change.
Main:
driver = startup_login('https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls')
team = "Chicago"
proline_go_to_match2(driver,team)
Functions:
def proline_go_to_match2(driver, team):
#print(team)
try:
match = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li[1]//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]")) )
match.click()
except:
driver.quit()
def proline_go_to_match3(driver, team):
#print(team)
try:
match = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.XPATH, "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li[2]//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]")) )
match.click()
except:
driver.quit()
for your xpath, it can find two elements, you can try the following code, it can work well, opening browser will implicit to wait for page ready.
from clicknium import clicknium as cc
if not cc.chrome.extension.is_installed():
cc.chrome.extension.install_or_update()
def get_elements(tab,team):
xpath = "//ul[@class='fdjgs-markets']/li[@class='fdjgs-market']//ul[@class='fdjgs-outcomes']//descendant::li//span[@class='fdjgs-outcome-wrapper' and contains(@aria-label, '"+ team +"')]/span[starts-with(., '"+ team +"')]"
return tab.find_elements_by_xpath(xpath)
tab = cc.chrome.open("https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls")
elements = get_elements(tab, "Chicago")
for elem in elements:
elem.click()
elements = get_elements(tab, "Miami")
for elem in elements:
elem.click()
You have to add some wait time in the function and you don’t need to use 2 functions to do click operations on 2 different team names, you can use just one, like below:
def proline_go_to_match(driver, team):
try:
time.sleep(4)
match = WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH,"(.//span[@class='fdjgs-outcome-wrapper' and @title=contains(.,'" + team + "')])[1]")))
match.click()
except:
driver.quit()
Always, try to use simplified Xpath.
You can pass any value to the argument – ‘team’ like "Chicago" or "Miami".
Check for consent and click on that if exists.
use python format() function to change the parameter.
Use js executor to click else will get element intercepted error you can use actionchain as well.
driver.get("https://prolineplus.olg.ca/en-ca/event/?e177405-Basketball-NBA-USA-Miami-Heat-Chicago-Bulls")
wait=WebDriverWait(driver,20)
#check for consent
try:
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[text()='Continue']"))).click()
except:
pass
team="Chicago"
items=wait.until(EC.visibility_of_all_elements_located((By.XPATH, "//span[contains(@aria-label, '{0}')]//span[starts-with(., '{0}')]".format(team))))
for item in items:
driver.execute_script("arguments[0].click();", item)
print("Button clicked")
Three things that could help: (1) Using equivalent JavaScript
rather than the Selenium
click method; (2) using an explicit wait in finding the element you want to be clicked; and (3) injecting driver options that make you appear more like a legitimate user, less like a bot.
(1) Executing JS to click
Don’t use the Selenium
click method:
some_element_name.click()
Do this instead:
driver.execute_script("arguments[0].click();", some_element_name)
(2) Add waits
We want to give the page time to render first. We could use, say, time.sleep(n)
but it’s significantly better to do an explicit wait, that waits until <condition>
. So, don’t do this:
click_target = driver.find_element(By.<method>, '<tag>')
Do this instead:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 15)
click_target = wait.until(EC.presence_of_element_located((By.<method>, '<tag>')))
(3) Optimizing driver options for covertness
Keep it discreet that we’re a bot.
from selenium.webdriver.chrome.options import Options # chrome example
options = Options()
options.add_argument("--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36") # legit looking user agent
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_argument("disable-infobars")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options) # then init with options