Error "Other element would receive the click" in Python - python-3.x

I tried to click a link like this:
<div class="loading" style="display:none;">
<p class="btn blue"><span>さらに表示</span></p>
</div>
and I used this code:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_css_selector(".btn.blue")) # #UnusedVariable
element.click()
I got an error like this, what can I do to solve it?
selenium.common.exceptions.WebDriverException: Message: unknown error: Element <p class="btn blue">...</p> is not clickable at point (391, 577). Other element would receive the click:
(Session info: headless chrome=69.0.3497.100)
(Driver info: chromedriver=2.41.578737 (49da6702b16031c40d63e5618de03a32ff6c197e),platform=Windows NT 6.1.7601 SP1 x86_64)

Element on which you are trying to click has been covered by some other element so that other element getting the click instead of the actual element.
There may be following possibilities that actual element not getting clicked:
Case 1. lets say if its a loader which comes while your element getting load and get invisible after some time.
Solution: Here you have to wait until the loader get invisible and then have to perform click on actual element
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.invisibility_of_element_located((By.ID, 'loader_element_id')))
element_button = wait.until(EC.element_to_be_clickable((By.ID, 'your_button_id')))
element_button.click()
Case 2. actual element is not visible within browser dimension and covered by some overlay element.
Solution: Here you need to scroll to the required element and then have to perform the click
from selenium.webdriver.common.action_chains import ActionChains
element = driver.find_element_by_id("your_element_id")
actions = ActionChains(driver)
actions.move_to_element(element).perform()
OR use can use execute_script like :
driver.execute_script("arguments[0].scrollIntoView();", element)
OR perform the click using JavaScript.
driver.execute_script("arguments[0].click();", element)
Note: Please make necessary correction as per Python syntax if require.

You may use action class to click your element,
from selenium.webdriver import ActionChains
actions = ActionChains(driver)
actions.move_to_element(element).click().perform()

As per the HTML and your code trials you have attempted to click on the <span> tag in stead you should try to invoke click() on the <a> tag as follows:
Using css_selector:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_css_selector("div.loading a[onclick^='get_more']"))
element.click()
Using xpath:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_xpath("//p[#class='btn blue']/span[contains(.,'さらに表示')]//following::a[contains(#onclick,'get_more')]"))
element.click()

This is my function for click element on every condition:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
def xpathElement(driver, xpath):
return WebDriverWait(driver, config['waitSeconds']).until(EC.presence_of_element_located((By.XPATH, xpath)))
def scroll2elementByXpath(driver, xpath):
element = xpathElement(driver, xpath)
element.location_once_scrolled_into_view
def clickObject(driver, xpath, firstTime=True, useJS=False):
try:
element = xpathElement(driver, xpath)
if useJS:
driver.execute_script("arguments[0].click();", element)
else:
element.click()
except Exception as exception:
if firstTime:
scroll2elementByXpath(driver, xpath)
clickObject(driver, xpath, desc, False)
elif not useJS:
clickObject(driver, xpath, desc, firstTime, True)
else:
assert False, exception

Related

Why do I get the error "Element could not be scrolled into view" unless I manually scroll the browser instance?

I wrote a python script that goes to a site, and interacts with some dropdowns. It works perfectly fine if after I run the script, quickly make the browser instance full screen so that the elements are in view. If I don't do that, I get the error "Element could not be scrolled into view".
Here is my script:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://example.com")
driver.implicitly_wait(5)
yearbtn = driver.find_element("id", "dropdown_year")
yearbtn.click()
year = driver.find_element("css selector", '#dropdown_ul_year li:nth-child(5)')
year.click()
makebtn = driver.find_element("id", "dropdown_make")
makebtn.click()
make = driver.find_element("css selector", '#dropdown_ul_make li:nth-child(2)')
make.click()
modelbtn = driver.find_element("id", "dropdown_model")
modelbtn.click()
model = driver.find_element("css selector", '#dropdown_ul_model li:nth-child(2)')
model.click()
trimbtn = driver.find_element("id", "dropdown_trim")
trimbtn.click()
trim = driver.find_element("css selector", '#dropdown_ul_trim li:nth-child(2)')
trim.click()
vehicle = driver.find_element("css selector", '#vehiclecontainer > div > p')
vdata = driver.find_element("css selector", '.top-sect .tow-row:nth-child(2)')
print("--------------")
print("Your Vehicle: " + vehicle.text)
print("Vehicle Data: " + vdata.text)
print("--------------")
print("")
driver.close()
Like I said, it works fine if I make the browser full-screen (or manually scroll) so that the elements in question are in view. It finds the element, so what's the issue here? I've tried both Firefox and Chrome.
Generally firefox opens in maximized mode. Incase for specific version of os it doesn't, the best practice is to open it in maximized mode as follows:
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
options = Options()
options.add_argument("start-maximized")
driver = webdriver.Firefox(options=options)
However in somecases the desired element may not get rendered within the due coarse, so you need to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following locator strategies:
vehicle = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#vehiclecontainer > div > p")))
vdata = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".top-sect .tow-row:nth-child(2)")))
print("--------------")
print("Your Vehicle: " + vehicle.text)
print("Vehicle Data: " + vdata.text)
print("--------------")
print("")
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
You can find a relevant discussion in How to retrieve the text of a WebElement using Selenium - Python
I'm not sure what all is happening on the page in question. I use a generic method to take care of common actions like click(), find(), etc. that contain a wait, scroll, and whatever else is useful for that action. I've put an example below. It waits for the element to be clickable (always a best practice), scrolls to the element, and then clicks it. You may want to tweak it to your specific use but it will get you pointed in the right direction.
def click(self, locator):
element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable(locator))
driver.execute_script("arguments[0].scrollIntoView();", element)
element.click()
I would suggest you try this and then convert all of your clicks to use this method and see if that helps, e.g.
click((By.ID, "dropdown_year"))
or
locator = (By.ID, "dropdown_year")
click(locator)

Selenium Python: The second loop in the program isn't geting executed

my code not working when reaching the second loop. when I hover over the first category it's showing the second category and I need to hover the second category to see the third category. here is my code:
driver.get("https://www.daraz.com.bd/")
main_category = driver.find_elements(By.CSS_SELECTOR , '.lzd-site-menu-root-item span')
for i in main_category:
hover = ActionChains(driver).move_to_element(i)
hover.perform()
time.sleep(1)
sub_category_one = driver.find_elements(By.CSS_SELECTOR , ".Level_1_Category_No1 [data-spm-anchor-id] span")
for i in sub_category_one:
hover = ActionChains(driver).move_to_element(i)
hover.perform()
To Mouse Hover over the first category which shows the second categories and then to Hover over the second categories to see the third categories you need to induce WebDriverWait for the visibility_of_all_elements_located() and you can use the following locator strategies:
Code block:
driver.get('https://www.daraz.com.bd/')
main_category = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, ".lzd-site-menu-root-item span")))
for i in main_category:
ActionChains(driver).move_to_element(i).perform()
time.sleep(1)
sub_category_one = WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "ul.Level_1_Category_No1 li.lzd-site-menu-sub-item")))
for j in sub_category_one:
ActionChains(driver).move_to_element(j).perform()
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
First of to scrape the site, bs4 and iterating over the lists seems like a much better approach.
Now find_elements returns a list. You are iterating over a list with only one value in your second for loop. When I inspected the page I noticed that a submenu or subsubmenu that is active is assigned the class lzd-site-menu-sub-active and lzd-site-menu-grand-active.
main_category = driver.find_elements(By.CSS_SELECTOR, ".lzd-site-menu-root-item span")
for main in main_category:
ActionChains(driver).move_to_element(main).perform()
sub_category = WebDriverWait(driver, 3).until(
lambda x: x.find_elements(By.CSS_SELECTOR, ".lzd-site-menu-sub-item span")
)
for sub in sub_category:
ActionChains(driver).move_to_element(sub).perform()
subsub_category = WebDriverWait(driver, 3).until(
lambda x: x.find_elements(By.CSS_SELECTOR, ".lzd-site-menu-grand-item span")
)
for subsub in subsub_category:
ActionChains(driver).move_to_element(subsub).perform()
This code manages to go hover over the third level as you will see. However because of the bad CSS_Selector it's somewhat useless.
I hope this could be of help.

selenium.common.exceptions.NoSuchElementException error trying to identify element to click using Selenium and Python

despite numerous tries I'm unable to perform the following action(s).
I need to land on a page that contains one or more table rows/columns. For each (sequentially) I need to click on an arrow that opens a pop-up, close the window, then rinse and repeat.
Problem: I am unable to click on the item
Error:
class 'selenium.common.exceptions.NoSuchElementException'
Snippet of code that prompts the error:
[...]
driver = webdriver.Chrome('chromedriver.exe')
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--incognito")
# MODIFY URL HERE
driver.get(url)
[..]
try:
# arf = driver.find_element_by_name("ctl00_ContentPlaceHolder1_d_dettaglio_ctl02_button1").click()
arf = driver.find_element_by_xpath('//input[#id="ctl00_ContentPlaceHolder1_d_dettaglio_ctl02_button1"]').click()
pprint.pprint(arf)
except NoSuchElementException:
print ("error!", NoSuchElementException)
driver.close()
exit()
HTML element I need to interact with:
<td align="center">
<input type="image" name="ctl00$ContentPlaceHolder1$d_dettaglio$ctl02$button1" id="ctl00_ContentPlaceHolder1_d_dettaglio_ctl02_button1" src="../images/spunta_maggiore.gif" style="height:22px;width:22px;border-width:0px;">
</td>
Things I've tried:
driver.find_element_by_xpath (//input[#id etc...]) or driver.find_element_by_xpath('//input[#name])
driver.find_element_by_name("ctl00_ContentPlaceHolder1_d_dettaglio_ctl02_button1").click()
driver.find_element_by_id("ctl00_ContentPlaceHolder1_d_dettaglio_ctl02_button1").click()
In both cases, a no element found exception is raised.
What am I doing wrong ?
The desired element is a dynamic element so to click on the element you have to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input[type='image'][name*='ContentPlaceHolder'][id*='d_dettaglio'][src*='images/spunta_maggiore']"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[contains(#name, 'ContentPlaceHolder') and contains(#id, 'd_dettaglio')][#type='image' and contains(#src, 'images/spunta_maggiore.gif')]"))).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
References
You can find a couple of relevant discussions on NoSuchElementException in:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element while trying to click Next button with selenium
selenium in python : NoSuchElementException: Message: no such element: Unable to locate element

unable to click the dropdown element in selenium

i tried so many xpath in selenium but all were unable to click the element and always give me a error element not found or element not interactable
how to solve it any help would be appreciated
Here is xpath of the Element is give Below:
(//a[#href='javascript:void(0)' and #class='select2-choice select2-default'])[1]
Try with ".//*[#id='s2id_search_input']/a"
Wait for element to be clickable before click on it:
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)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#s2id_search_input a.select2-choice'))).click()
With scroll:
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#s2id_search_input a.select2-choice')))
driver.execute_script('arguments[0].scrollIntoView()', element)
element.click()
Click using JavaScript:
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#s2id_search_input a.select2-choice')))
driver.execute_script('arguments[0].click()', element)

double click visual element not in html to make textarea appear selenium

I want to enter text into a textarea. The problem is the textarea is only created and shows up in the html after clicking twice on a visual element in the browser.
For this visual element Dubbelklik om je tekst te typen, I cannot find an element in the html that refers to it and perform a double_click(). There are only containers, that either are unclickable elements, or allow clicks, but don't perform an action.
Up until here it works and the visual cue to double click appears slightly below the center:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait as wait
driver = webdriver.Chrome()
driver.get("https://www.hallmark.nl/kaarten/verjaardag-man/")
#wait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[href*='https://www.hallmark.nl:443/kaarten/verjaardag-man/grappig-m/make-that-the-cat-wise/happy-bursdeej-to-jou-3415094.aspx']"))).click()
wait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[href*='https://www.hallmark.nl:443/kaarten/verjaardag-man/grappig-m/hallmark/een-jaguar-voor-je-verjaardag-3346861.aspx']"))).click()
wait(driver, 10).until(EC.element_to_be_clickable((By.ID, "btnShowSizepicker"))).click()
wait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Standaard']"))).click()
wait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class, 'showDesktop')]//button[contains(text(),'Binnenkant')]"))).click()
But from then on I can't seem to find anything to make selenium click on the element.
I have tried clicking the things I can locate in the html:
# elem = driver.find_element_by_xpath("//div[contains(#class, 'canvasAnchor')]").click()
This gives an element not interactable error. I have also tried using an offset for a findable element:
elem = driver.find_element_by_class_name("canvas-container")
print(elem.location)
print(elem.size)
action = webdriver.common.action_chains.ActionChains(driver)
action.move_to_element_with_offset(elem, 0.5*elem.location.get('x'), (0.5*elem.location.get('y'))) #should click in the middle of this container
action.double_click()
action.perform()
But for different elements and values of x and y, I can only get it to do either nothing, or click on the contact sidebar (which highlights the word 'Neem').
If I click twice manually, a textarea appears in the html and I can execute send_keys('hello world')
The element where you have to click is actually canvas, so what you have to do is that move cursor to the position where double click is needed and then click there.
I tried this over your code and worked for me:
from selenium.webdriver.common.action_chains import ActionChains
elem = driver.find_element_by_xpath('//*[#class="canvasWrapper active"]//*[#class="canvas-container"]')
ActionChains(driver).move_to_element_with_offset(elem, 70, 60).double_click().perform()
Note:You may have to wait for the canvas element to load properly. I just tried from prompt.
You can read about this mouse action here.
UPDATE:
I noticed that somehow the double click was behaving as single click for me, so changed to this.
from selenium.webdriver.common.action_chains import ActionChains
import time
elem = driver.find_element_by_xpath('//*[#class="canvasWrapper active"]//*[#class="canvas-container"]')
ActionChains(driver).move_to_element_with_offset(elem, 70, 60).click().perform()
time.sleep(1)
ActionChains(driver).move_to_element_with_offset(elem, 70, 60).click().perform()

Resources