Python Selenium can't find element by Class Name and xpath - selenium

I try to use Selenium to perform click Download button at Historical Data/Time and Sales Historical Data section in webpage: https://www.sgx.com/research-education/derivatives.
I tried the code below:
sgxMainPageUrl = "https://www.sgx.com/research-education/derivatives"
# downloadButtonClassName = "sgx-button--primary"
downloadButtonXpath = "//widget-reports-derivatives-tick-and-trade-cancellation//button[contains(#class,'sgx-button--primary')]"
driver = webdriver.Chrome(chromedriver_path)
driver.get(sgxMainPageUrl)
# search = driver.find_element_by_class_name(downloadButtonClassName)
search = driver.find_element_by_xpath(downloadButtonXpath)
But it returns:
File "...\\AppData\Local\Programs\Python\Python38-32\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//widget-reports-derivatives-tick-and-trade-cancellation//button[contains(#class,'sgx-button--primary')]"}
I read several post and they faced this problem because duplicate xpath but this xpath is unique. Please help me explain why, many thanks!

There's an Accept cookies button, you need to click first. after that you can use the below xpath to click on download button :
(//button[text()='Download'])[1]
Code :
driver.get(sgxMainPageUrl)
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[class*='banner-acceptance-button']"))).click()
wait.until(EC.element_to_be_clickable((By.XPATH, "(//button[text()='Download'])[1]"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

You should add a wait to let the page loaded before accessing that element.
Try this:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 20)
wait.until(EC.visibility_of_element_located((By.XPATH, downloadButtonXpath))).click()

Related

Get text inside the href link inside the span marker using Selenium

How to extract the text which is displayed as part of the link inside the span marker.
<span class="pull-left w-100 font30 medium_blue_type mb10"><a href='/XLY'>XLY</a></span> <span class="w-100">Largest Allocation</span>
Output:
XLY
I've tried several approaches, among all, using
elems = driver.find_elements_by_class_name("span.pull-left.w-100.font30.medium_blue_type.mb10")
elems = driver.find_element_by_xpath('.//span[#class = "pull-left w-100 font30 medium_blue_type mb10"]')
but can't get it working. The website is https://www.etf.com/stock/TSLA.
EDIT:
Is it possible to do it without opening the window in the browser, e.g. using "headless" option?
op = webdriver.ChromeOptions()
op.add_argument('headless')
driver = webdriver.Chrome(CHROME_DRIVER_PATH, options=op)
If you prefer to have a text-based locators, you can use the below:
//span[text()='Largest Allocation']/../span
You should click on the cookies I understand button first.
Make use of explicit waits.
So your effective code would be:
driver = webdriver.Chrome(driver_path)
driver.maximize_window()
wait = WebDriverWait(driver, 30)
driver.get("https://www.etf.com/stock/TSLA")
try:
wait.until(EC.element_to_be_clickable((By.LINK_TEXT, "I Understand"))).click()
print("Clicked on I understand button")
except:
pass
txt = wait.until(EC.visibility_of_element_located((By.XPATH, "//span[text()='Largest Allocation']/../span"))).text
print(txt)
Imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Output:
Clicked on I understand button
XLY
Process finished with exit code 0
If you are looking for locators not based on text, use the below line of code:
txt = wait.until(EC.visibility_of_element_located((By.XPATH, "(//span[contains(#class,'medium_blue_type')]//a)[2]"))).text
There are several possible problems here:
Maybe you are missing a delay
The locator you are using may be not unique
I can see here you are extracting the attribute value from the returned web element
The web element can be inside iframe etc.
Based on currently shared information you can try adding a wait and extracting the web element value as following:
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
wait = WebDriverWait(driver, 20)
href = wait.until(EC.visibility_of_element_located((By.XPATH, "//span[#class = "pull-left w-100 font30 medium_blue_type mb10"]"))).get_attribute("href")
Use the following xpath to identify the href link.
//div[./span[text()='Largest Allocation']]//a
You need to induce some delay to get the element.
Use WebDriverWait() and wait for visibility of the element.
To get the text:
print(WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.XPATH, "//div[./span[text()='Largest Allocation']]//a"))).text)
To get the href:
print(WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.XPATH, "//div[./span[text()='Largest Allocation']]//a"))).get_attribute("href"))
you need to import below libraries.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

Selenium Firefox Webdriver - need help locating button and with code to click button

I'm using Selenium and need to click on a button called Income Statement at http://www.tradingview.com/screener. Could anyone help me to find the button name and let me know if the code where I'm trying to implement it is correct. Any help much appreciated. Thanks!!
url = 'http://www.tradingview.com/screener'
driver = webdriver.Firefox()
driver.get(url)
button_element = driver.find_element_by_xpath("//input[#name='Income Statement']")
button_element.click()
There are 2 problems here:
You have to add wait / delay before accessing that element.
This should preferably be done by expected conditions explicit waits.
You are using a wrong locator.
This should work better:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
url = 'http://www.tradingview.com/screener'
driver = webdriver.Firefox()
wait = WebDriverWait(driver, 20)
driver.get(url)
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[#data-set='income_statement']"))).click()
Your xpath does not locate the right element in the HTMLDOM.
so instead of this:
//input[#name='Income Statement']
use this:
//div[#data-set='income_statement']
or
a CSS like this:
div[data-set = 'income_statement']
explanation:
See this is a outerHTML:
<div class="tv-screener-toolbar__favorites-item js-favorite-item" data-set="income_statement">
Income Statement
</div>
As we can see it is a div tag, so we are using //div and also it has data-set attribute income_statement and when you write the XPath, it is able to locate the right node with 1/1 uniqueness.
Also It's a best practise to use ExplicitWait:
wait = WebDriverWait(driver, 30)
try:
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[#data-set='income_statement']"))).click()
print('Clicked on the button')
except:
print('Could not click ')
pass
Imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Selenium will not click class id

I am trying to have selenium to do the following:
Open a website
Click on the search box
Type "Seattle" in the search box
Select the first result from the suggested results
My code fails at Step 2.
The class id for the search box is "class = input_search ng-pristine ng-valid ng-empty ng-touched"
Here's my code:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
url = 'https://wego.here.com/'
driver.get(url)
driver.find_element_by_css_selector('.input_search.ng-pristine.ng-valid.ng-empty.ng-touched').click()
driver.find_element_by_css_selector('.input_search.ng-pristine.ng-valid.ng-empty.ng-touched').send_keys('Seattle')
driver.find_element_by_css_selector('.input_search.ng-pristine.ng-valid.ng-empty.ng-touched').send_keys(Keys.ENTER)
Any suggestions would be greatly appreciated!
ADDITIONAL QUESTION
Thanks to #Prophet I was able to get the first auto-click and auto-fill done, but when I try to do the same task with a different search box, it does not like it. Please refer to the following code that I added to the existing code:
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "button.btn"))).send_keys(Keys.ENTER)
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input.itinerary_item_input_0"))).click()
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input.itinerary_item_input_0"))).send_keys('Chicago')
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input.itinerary_item_input_0"))).send_keys(Keys.ENTER)
button.btn did work, but not the input.itinerary_item_input_0. Here is the source screenshot:
You are using a wrong locator.
ng-empty and ng-touched may not be there all the times.
So instead of
driver.find_element_by_css_selector('.input_search.ng-pristine.ng-valid.ng-empty.ng-touched').click()
Try using this:
driver.find_element_by_css_selector('input.input_search').click()
input.input_search is an unique, stable locator for that element.
Also, you have to add a delay, preferably to use the expected conditions, as following:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 20)
url = 'https://wego.here.com/'
driver.get(url)
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input.input_search"))).click()
wait=WebDriverWait(driver, 60)
driver.get('https://wego.here.com/')
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"input.input_search"))).send_keys("Seattle")
wait.until(EC.element_to_be_clickable((By.XPATH,"//div[#class='dropdown_list']/div[1]"))).click()
This will select the first option after sending a string to input tag.
Imports:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

How can I click the "SORT BY" button and select "Newest first" item on YouTube video page?

As a beginner to Python, I've been trying to click the "SORT BY" button and select "Newest first" item on YouTube video page (Like the following picture shows).
I tried with the following code.
! pip install selenium
from selenium import webdriver
import time
driver = webdriver.Chrome('D:\chromedrive\chromedriver.exe')
driver.get("https://www.youtube.com/watch?v=ioNng23DkIM")
!pip install pynput
from pynput.mouse import Button, Controller
mouse = Controller()
mouse.scroll(0, -5)
time.sleep(1)
#click "SORT BY" button
driver.find_element('div#trigger.style-scope.tp-yt-paper-menu-button').click()
#click "Newest first" button
driver.find_elements_by_css_selector('#dropdown').click()
However, driver.find_element('div#trigger.style-scope.tp-yt-paper-menu-button').click() and driver.find_elements_by_css_selector('#dropdown').click() do not work. It kept showing the error of Message: invalid argument: invalid locator .
If anyone knows how to solve it, please help me.
try below code :
wait = WebDriverWait(driver, 10)
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.style-scope.yt-dropdown-menu:nth-of-type(1)"))).click()
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[text()='Newest first']"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
I think your code should do something like this:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
wait = WebDriverWait(driver, 20)
actions = ActionChains(driver)
sort_comments_xpath = "//*[#aria-label='Sort comments']"
newest_first_xpath = "//div[contains(text(),'Newest first')]"
sort_comments = wait.until(EC.presence_of_element_located((By.XPATH, sort_comments_xpath)))
actions.move_to_element(sort_comments).build().perform()
time.sleep(0.5)
sort_comments.click()
newest_first = wait.until(EC.visibility_of_element_located((By.XPATH, newest_first_xpath))).click()
Wait until sort comments element appears, scroll to it, click it.
Wait until newest first option appears, click on it.

Unable to locate element: Selenium

I want to select the More Information link by clicking on it. I have tried everything I could but every time the error NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector" pops up.
At first, I thought maybe because I did not change the tabs properly that's why this error is showing. But, even after using window_handles still I cannot locate any element on this page.
Please HELP!
self.driver.window_handles
base = self.driver.window_handles[0]
child = self.driver.window_handles[1]
window_set = {self.driver.window_handles[0], self.driver.window_handles[1]}
for x in window_set:
if(base != x):
self.driver.switch_to.window(x)
self.driver.find_element_by_id("mc-lnk-moreInfo").click()
Please check below solution using contains and ID
Xpath with contains
element= WebDriverWait(self.driver, 30).until(
EC.element_to_be_clickable((By.XPATH, '//*[contains(text(), 'More information')]')))
self.driver.execute_script("arguments[0].click();", element)
or
Xpath with ID
element= WebDriverWait(self.driver, 30).until(
ec.element_to_be_clickable((By.ID, "//a[#id='mc-lnk-moreInfo']")))
self.driver.execute_script("arguments[0].click();", element)
Working Solution :
driver = webdriver.Chrome(executable_path=r"C:\New folder\chromedriver.exe")
driver.maximize_window()
wait = WebDriverWait(driver, 10)
driver.get("your url")
childframe = wait.until(EC.presence_of_element_located((By.NAME, "mainFrame")))
driver.switch_to.frame(childframe)
element=wait.until(EC.element_to_be_clickable((By.ID, "mc-lnk-moreInfo")))
print element.text
element.click()
Note : please add below imports to your solution
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
Output:
Try to wait for the element then click on it
Replace
self.driver.find_element_by_id("mc-lnk-moreInfo").click()
With following
self.more_info = WebDriverWait(self.driver, 30).until(
ec.visibility_of_element_located((By.ID, "//a[#id='mc-lnk-moreInfo']")))
ActionChains(self.driver).move_to_element(self.more_info).click().perform()
add the following on with your imports
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec