Selenium webdriver python find element by xpath - Could not find element - python

I m trying to write a script with selenium webdriver python.
When I try to do a
find_element_by_xpath("//*[#id='posted_1']/div[3]")
it says
NoElementFoundException.
Can someone please help me here?
Regards
Bala

If you are getting NoSuchElementException as your provided exception, There may be following reasons :-
May be you are locating with incorrect locator, So you need to share HTML for better locator solution.
May be when you are going to find element, it would not be present on the DOM, So you should implement WebDriverWait to wait until element visible as below :-
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, 10)
element = wait.until(EC.visibility_of_element_located((By.XPATH, "//*[#id='posted_1']/div[3]")))
May be this element is inside any frame or iframe. If it is, you need to switch that frame or iframe before finding the element as below :-
driver.switch_to_frame("frame/iframe I'd or name")
wait = WebDriverWait(driver, 10)
element = wait.until(EC.visibility_of_element_located((By.XPATH, "//*[#id='posted_1']/div[3]")))
#Once all your stuff done with this frame need to switch back to default
driver.switch_to_default_content();

that exception, unsurprisingly, means that that element wasn't available on the DOM. There are a couple of options here:
driver.implicitly_wait(10)
will tell the driver to wait 10 seconds (or any amount of time) after an element is not found/not clickable etc., and tries again after. Sometimes elements don't load right away, so an implicit wait fixes those types of problems.
The other option here is to do an explicit wait. This will wait until the element appears, and until the existence of that element is confirmed, the script will not move on to the next line:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(ff, 10).until(EC.presence_of_element_located((By.XPATH, "//*[#id='posted_1']/div[3]")))
In my experience, an implicit wait is usually fine, but imprecise.

Related

Issue with selenium.webdriver click function using find_elements(By.XPATH, [duplicate]

I'd like to click the button 'Annual' at a page that is by default set on 'Quarterly'. There are two links that are basically called the same, except that one has data-ptype="Annual" so I tryed to copy the xpath to click the button (also tried other options but none did work).
However, I get the AttributeError: 'list' object has no attribute 'click'. I read a lot of similar posts, but wasn't able to fix my problem.. so I assume that javascript event must be called/clicked/performed somehow differnt.. idk Im stuck
from selenium import webdriver
link = 'https://www.investing.com/equities/apple-computer-inc-balance-sheet'
driver = webdriver.Firefox()
driver.get(link)
elm = driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
The html is the following:
<a class="newBtn toggleButton LightGray" href="javascript:void(0);" data-type="rf-type-button" data-ptype="Annual" data-pid="6408" data-rtype="BAL">..</a>
you need to use find_element_by_xpath not find_elements_by_xpath that return a list
driver.find_element_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
Also i think is better to use Waits for example.
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.firefox.options import Options
options = Options()
options.add_argument("--window-size=1920,1080")
driver = webdriver.Firefox(firefox_options=options)
path = "/html/body/div[5]/section/div[8]/div[1]/a[1]"
try:
element = WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.XPATH, path)))
element.click()
finally:
driver.quit()
I would still suggest you to go with linkText over XPATH. Reason this xpath : /html/body/div[5]/section/div[8]/div[1]/a[1] is quite absolute and can be failed if there is one more div added or removed from HTML. Whereas chances of changing the link Text is very minimal.
So, Instead of this code :
elm = driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
try this code :
annual_link = driver.find_element_by_link_text('Annual')
annual_link.click()
and yes #Druta is right, use find_element for one web element and find_elements for list of web element. and it is always good to have explicit wait.
Create instance of explicit wait like this :
wait = WebDriverWait(driver,20)
and use the wait reference like this :
wait.until(EC.elementToBeClickable(By.LINK_TEXT, 'Annual'))
UPDATE:
from selenium import webdriver
link = 'https://www.investing.com/equities/apple-computer-inc-balance-sheet'
driver = webdriver.Firefox()
driver.maximize_window()
wait = WebDriverWait(driver,40)
driver.get(link)
driver.execute_script("window.scrollTo(0, 200)")
wait.until(EC.element_to_be_clickable((By.LINK_TEXT, 'Annual')))
annual_link = driver.find_element_by_link_text('Annual')
annual_link.click()
print(annual_link.text)
make sure to import these :
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
As per the documentation find_elements_by_xpath(xpath) returns a List with elements if any was found or else an empty list if not. Python's List have no click() method associated with it. Instead find_element_by_xpath(xpath) method have the click() method associated with it. So you have to use find_element_by_xpath(xpath) method inducing a waiter through WebDriverWait inconjunction with expected_conditions set as element_to_be_clickable(locator) as follows:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='newBtn toggleButton LightGray' and #data-type='rf-type-button']"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Notice that find_elements_by_xpath is plural it returns a list of elements. Not just one. The list can contain none, exactly one, or more elements.
You can for example click the first match with:
driver.find_elements_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]")[0].click()
or iterate through the list and click all these elements, or you can use the find_element_by_xpath (which returns a single element, if it can be found):
driver.find_element_by_xpath("/html/body/div[5]/section/div[8]/div[1]/a[1]").click()
For me, it was not working, and tried a hell lot of tricks, and none worked. Some people recommended driver.implicitly_wait(10) instead of time.sleep(10) which didn't work. so please try giving time.sleep(10) both above and below the .click() code line, and check if it works or not.

Python Selenium - send_keys not sending any information to element

I am trying out Selenium for the first time so I apologize if there is an obvious mistake or problem with my code.
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://youtube.com')
searchBox = driver.find_element_by_id('search')
searchBox.send_keys('Programming')
searchButton = driver.find_element_by_id('search-icon-legacy')
searchButton.click()
So I tried this and it loads the page fine but, it does not input any characters into the searchBox (I quadruple checked that the id was correct - copied it directly from the inspector).
NOTE:
My internet is really REALLY slow and it takes YouTube approx. 20 seconds to fully load, so I thought that was an issue so I tried;
...
driver.get('https://youtube.com')
driver.implicitly_wait(30)
searchBox = driver.find_element_by_id('search')
...
But this did not work either.
I did use XPATH instead of finding it by element ID at the start and that did not work.
I checked and copied the XPATHs and IDs directly from the inspector and nothing so far has inputted anything into the textbox.
What could be the problem? (1)
and does the webdriver wait for the page to load/find the element before doing anything after it being initialized with the driver.get('websiteAddress')? (2)
NOTE: I double checked that I was selecting the right element as well.
To send keys to the input tag with id = search. We use webdriver waits to allow the element to be usable after driver.get so the page loads correctly.
driver.get('https://youtube.com')
WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.XPATH, "//input[#id='search']"))).send_keys("Programming")
Import
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
If you don't know the waiting time:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
delay = 40
WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.XPATH, "//form[#role='form']//input[#id='username']")))
Then it just waits on the element, for as log as delay is, but will continue as soon as the element is found, that the best way to wait on slow connections.
To relate elements more easily you can use ChroPath, it is an extension for google chrome / edge that allows you to see the path of an element, through cssSelector, Abs XPath, Rel XPath and the tag name, so when your code is not working you can try these other ways. Particularly this extension helps me a lot.

Selenium Python | Wait for Entire Page to Load, Not Dependant on a Dynamic Element

I've seen similar questions to this but no one has given me a clear answer on whether or not it is possible for Selenium to know whether the entire page has loaded or not.
I know about expected_conditions.visibility_of_element_located((By.TAG_NAME, "div")) but I do not want a dynamic element to look for. I also don't want to wait a set number of seconds, I need the program to continue as soon as the entire page is loaded.
Is this possible?
You can use selenium webdriverWait:
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
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
In the code above, Selenium will wait for a maximum of 10 seconds for an element matching the given criteria to be found. If no element is found in that time, a TimeoutException is thrown.
Or you can use the time module:
import time
time.sleep(10)
In the code above the program will wait for 10 seconds before executing the next line.

Python Selenium Unable to find an element inside Frameset > Frame

How can I find the highlighted element in the following html structure.
Target element highlighted
This is the code that I'm using.
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
browser = webdriver.Edge()
browser.implicitly_wait(5) # seconds
browser.get(url) # aspx page
browser.find_element_by_id("LoginBtn").click()
browser.find_element_by_id("ReportingMenuName").click()
browser.find_element_by_id("EndpointDataExportSubmenuName").click()
browser.find_element_by_id("EndpointDataExportMenuItem").click()
browser.switch_to_default_content()
browser.switch_to.frame(browser.find_element_by_id("main"))
element = WebDriverWait(browser, 10).until(EC.presence_of_element_located(\
(By.ID, "ct100_PageBody_OkButton")))
element.click()
When I run the code I get this error when it reaches the last 2 lines of code:
TimeoutException
If I change the last 2 lines of code for this, then I get another error.
browser.find_element_by_id("ct100_PageBody_OkButton").click()
NoSuchElementException: No such element
There are a couple of things you need to consider :
While you access/login to a url Selenium's focus is on the Top Level Browsing Context. So before switching to any frame you don't need to switch_to_default_content(). Hence you can omit the line :
browser.switch_to_default_content()
While you switch to frame through switch_to.frame() induce WebDriverWait with the clause frame_to_be_available_and_switch_to_it for the frame to be available for switching as follows :
WebDriverWait(browser, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"main")))
Within the frame once you identify the element moving ahead as you are invoking click() so instead of expected_conditions as presence_of_element_located you need to use element_to_be_clickable as follows :
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[#class='buttontext' and contains(#id,'_PageBody_OkButton')]"))).click()

Selenium wait until method

I am new to using Selenium and am trying to work out how to use the wait until method on the website booking.com, to wait for the dropdown options to be visible as in the image.
This is the code I am working with:
driver.get('http://booking.com')
driver.find_element_by_css_selector('#ss').send_keys("London")
WebDriverWait(driver,1).until('PLEASE SUGGEST WHAT TO INPUT')
driver.find_element(By.XPATH, """//*[#id="frm"]/div[2]/div/div[1]/ul[1]/li[1]""").click()
Using the chrome inspector, I cannot see any clear selector or element to use in the parentheses for the until method. When i right-click on the visible options and click 'Copy selector' I just get this:
#frm > div:nth-child(8) > div > div.c-autocomplete.sb-destination > ul.c-autocomplete__list.sb-autocomplete__list.-visible > li.c-autocomplete__item.sb-autocomplete__item.sb-autocomplete__item--city
Please can someone suggest what I need to do here.
Try this code:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('http://booking.com')
driver.find_element_by_css_selector('#ss').send_keys("London")
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".search_hl_name")))
driver.find_elements(By.XPATH, "//*[#class ='search_hl_name']")[1].click() // you can use relative xpath in place of absolute one, replace index value at [1] with 0-4 which ever you want to select
As rightly mentioned by Andersson you need to increase the timeout
You can try to wait until one of drop-down options become clickable with ExpectedConditions:
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
driver.find_element_by_css_selector('#ss').send_keys("London")
WebDriverWait(driver,5).until(EC.element_to_be_clickable((By.XPATH, '//li[#class="c-autocomplete__item sb-autocomplete__item sb-autocomplete__item--city sb-autocomplete__item--two-lines "]')))
Note that second argument you pass in WebDriverWait() is timeout (in seconds) and 1 second might be not enough to wait for expectation met
To select required option you might use more verbose relative XPath instead of absolute one:
driver.find_element(By.XPATH, '//li//b[text()="Central London"]').click()
This should select option with bold text "Central London". Just replace "Central London" with appropriate value to select another option

Categories