I want to locate the elements of a popup on some page,
the popup html is written in an iframe,
also the popup is triggered by clicking a link on the main page.
The weird thing is, if I run the whole code, I can not locate the 'target' element:
dr = webdriver.Chrome('chromedriver.exe', options=chrome_options)
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
def ec_visible(driver, locator):
return WebDriverWait(driver, 5).until(EC.visibility_of_element_located(locator))
But, if I first open the popup then locate, it works.
First:
modify = (By.CLASS_NAME, "modify")
ec_visible(dr, modify).click()
#popup = (By.CLASS_NAME, "add-addr-iframe")
#dr.switch_to.frame(ec_visible(dr, popup))
#target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
#ec_visible(dr, target).click()
Then: (works too if I manually open the popup and run this code)
#modify = (By.CLASS_NAME, "modify")
#ec_visible(dr, modify).click()
popup = (By.CLASS_NAME, "add-addr-iframe")
dr.switch_to.frame(ec_visible(dr, popup))
target = (By.CLASS_NAME, "cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
Appreciate if you can point out my problem!
Here is the exception from shell:
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
This is the html screenshot,
sometimes the content in iframe can not even be seen.
iframe not extendable
when iframe extendable
7/26 update
I am wondering whether I asked the right question which may lead you guys just focusing on my code part. Since my code works(seperately), the elements and frames approach are good.
I step back and find one detail which may help but I don't know how it matters.
Here are the two shots about ctrl-F some element in the page source:
Normal result: target found and highlighted
Weird result: target found and no highlight
I mean when the page exists 'weird result', my code does not work.
PS. The page is the order-confirmation part of an e-commerical site, but the site groups its goods into two types which led to TWO types order page.
For ifarmes you have frame_to_be_available_and_switch_to_it as the EC.
So try this:
WebDriverWait(driver, 5).until(EC.frame_to_be_available_and_switch_to_it((By.CLASS_NAME, "add-addr-iframe")))
target = (By.CLASS_NAME, "span.cndzk-entrance-division-header-click")
ec_visible(dr, target).click()
Related
I have seen other questions about this error but my case is that in my program the other element should receive the click. In details: the webdriver is scrolling through google search and it must click every website it finds but the program is preventing that. How can I make it NOT search the previous site it clicked?
This is the function. The program is looping it and after the first loop it scrolls down and the error occurs:
def get_info():
browser.switch_to.window(browser.window_handles[2])
description = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "h3"))
).text
site = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "cite"))
)
site.click()
url=browser.current_url
#removes the https:// and the / of the url
#to get just the domain of the website
try:
link=url.split("https://")
link1=link[1].split("/")
link2=link1[0]
link3=link2.split("www.")
real_link=link3[1]
except IndexError:
link=url.split("https://")
link1=link[1].split("/")
real_link=link1[0]
time.sleep(3)
screenshot=browser.save_screenshot("photos/"+"(" + real_link + ")" + ".png")
global content
content=[]
content.append(real_link)
content.append(description)
print(content)
browser.back()
time.sleep(5)
browser.execute_script("window.scrollBy(0,400)","")
time.sleep(5)
You can create a list of clicked website and check every time if that link is clicked or not. Here's the demo code :
clicked_website=[]
url=browser.current_url
clicked_website.append(url)
# Now while clicking
if <new_url> not in clicked_website:
<>.click()
This is just an idea how to implement. Your code is mess, I didn't understand clearly so, implement in your code by yourself.
I'm trying to open a website using Selenium, find a specific search box within it and fill it with a company name (MAGAZINE LUIZA S.A. in the example) and then click the "Search" button right next to the search box, since it will not work if I just hit "enter".
nav = webdriver.Edge()
nav.implicitly_wait(10)
nav.get('http://www.b3.com.br/pt_br/produtos-e-servicos/negociacao/renda-variavel/empresas-listadas.htm')
nav.find_element_by_xpath("/html/body/form/div[3]/div[1]/div/div/div/div/div[3]/div[1]/div[1]/div[2]/div[1]/div/div[1]/label/span[1]/input[1]").send_keys('MAGAZINE LUIZA S.A.')
nav.find_elements_by_xpath('/html/body/form/div[3]/div[1]/div/div/div/div/div[3]/div[1]/div[1]/div[2]/div[1]/div/div[2]/input').click()
And I get the Xpath of the search bar and search button by inspecting them and "copying full Xpath" in Microsoft Edge.
Problem is I get this error:
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"/html/body/form/div[3]/div[1]/div/div/div/div/div[3]/div[1]/div[1]/div[2]/div[1]/div/div[1]/label/span[1]/input[1]"}
(Session info: MicrosoftEdge=91.0.864.54)
But I have verified that I have copied and pasted the correct Xpaths for both the commands. Can anyone help?
You need to handle iframe, that XPath is relative to iframe.
This is your modified code
nav = webdriver.Edge()
nav.implicitly_wait(10)
nav.get('http://www.b3.com.br/pt_br/produtos-e-servicos/negociacao/renda-variavel/empresas-listadas.htm')
iframe = nav.find_element_by_xpath('/html/body/main/div[4]/div/div[1]/div[1]/div/form/section/div/div/div/iframe')
nav.switch_to.frame(iframe)
inp = nav.find_element_by_xpath("/html/body/form/div[3]/div[1]/div/div/div/div/div[3]/div[1]/div[1]/div[2]/div[1]/div/div[1]/label/span[1]/input[1]")
inp.send_keys('MAGAZINE LUIZA S.A.')
nav.find_element_by_xpath('/html/body/form/div[3]/div[1]/div/div/div/div/div[3]/div[1]/div[1]/div[2]/div[1]/div/div[2]/input').click()
I try find target element by xpath so that I can click on it. But can't find it when run code, although can find it by right-click option manually on chrome browser.
detail: I am using
driver.get('chrome://settings/clearBrowserData')
to get history pop-up from chrome, then wait element by selenium,
and next action I try to click it by:
driver.find_element_by_css_selector('* /deep/ #clearBrowsingDataConfirm').click()
or by:
driver.find_element_by_xpath(r'//paper-button[#id="clearBrowsingDataConfirm"]').click()
both does not work
Could you tell solution by xpath if possible because I am more familiar with it. Or any other way to clear history on chrome, thank
Looking into Chrome Settings page source it looks like the button, you're looking for is hidden in the ShadowDOM
So you need to iterate down several levels of ShadowRoot
So the algorithm looks like:
Locate parent WebElement
Locate its shadow-root and cast it to the WebElement
Use WebElement.find_element() function to locate the next WebElement which is the parent for the ShadowRoot
Repeat steps 1-3 until you're in the same context with the element you want to interact with
Example code:
from selenium import webdriver
def expand_root_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
driver = webdriver.Chrome("c:\\apps\\webdriver\\chromedriver.exe")
driver.maximize_window()
driver.get("chrome://settings/clearBrowserData")
settingsUi = driver.find_element_by_tag_name("settings-ui")
settingsUiShadowRoot = expand_root_element(settingsUi)
settingsMain = settingsUiShadowRoot.find_element_by_tag_name("settings-main")
settingsShadowRoot = expand_root_element(settingsMain)
settingsBasicPage = settingsShadowRoot.find_element_by_tag_name("settings-basic-page")
settingsBasicPageShadowroot = expand_root_element(settingsBasicPage)
settingsPrivacyPage = settingsBasicPageShadowroot.find_element_by_tag_name("settings-privacy-page")
settingsPrivacyShadowRoot = expand_root_element(settingsPrivacyPage)
settingsClearBrowsingDataDialog = settingsPrivacyShadowRoot.find_element_by_tag_name(
"settings-clear-browsing-data-dialog")
settingsClearBrowsingDataDialogShadowRoot = expand_root_element(settingsClearBrowsingDataDialog)
settingsClearBrowsingDataDialogShadowRoot.find_element_by_id("clearBrowsingDataConfirm").click()
I got it to work by doing this:
driver.ExecuteScript("return document.querySelector('body > settings-ui').shadowRoot.querySelector('#main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('#advancedPage > settings-section:nth-child(1) > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataConfirm').click();");
I am new to selenium here. I am trying to use selenium to click a 'more' button to expand the review section everytime after refreshing the page.
The website is TripAdvisor. The logic of more button is, as long as you click on the first more button, it will automatically expand all the review sections for you. In other words, you just need to click on the first 'more' button.
All buttons have a similar class name. An example is like taLnk.hvrIE6.tr415411081.moreLink.ulBlueLinks. Only the numbers part changes everytime.
The full element look like this:
<span class="taLnk hvrIE6 tr413756996 moreLink ulBlueLinks" onclick=" var options = {
flow: 'CORE_COMBINED',
pid: 39415,
onSuccess: function() { ta.util.cookie.setPIDCookie(2247); ta.call('ta.servlet.Reviews.expandReviews', {type: 'dummy'}, ta.id('review_413756996'), 'review_413756996', '1', 2247);; window.location.hash = 'review_413756996'; }
};
ta.call('ta.registration.RegOverlay.show', {type: 'dummy'}, ta.id('review_413756996'), options);
return false;
">
More </span>
I have tried several ways to get the button click. But since it is an onclick event wrapped by span, I can't successfully get it clicked.
My last version looks like this:
driver = webdriver.Firefox()
driver.get(newurl)
page_source = driver.page_source
soup = BeautifulSoup(page_source)
moreID = soup.find("span", class_=re.compile(r'.*\bmoreLink\b.*'))['class']
moreID = '.'.join(moreID[0:(len(moreID)+1)])
moreButton = 'span.' + moreID
button = driver.find_element_by_css_selector(moreButton)
button.click()
time.sleep(10)
However, I keep getting the error message like this:
WebDriverException: Message: Element is not clickable at point (318.5,
7.100006103515625). Other element would receive the click....
Can you advise me on how to fix the problem? Any help will be appreciated!
WebDriverException: Message: Element is not clickable at point (318.5, 7.100006103515625). Other element would receive the click....
This error to be occur when element is not in the view port and selenium couldn't click due to some other overlay element on it. In this case you should try one of these following solution :-
You can try using ActionChains to reach that element before click as below :-
from selenium.webdriver.common.action_chains import ActionChains
button = driver.find_element_by_css_selector(moreButton)
ActionChains(button).move_to_element(element).click().perform()
You can try using execute_script() to reach that element before click as :-
driver.execute_script("arguments[0].scrollIntoView(true)", button)
button.click()
You can try using JavaScript::click() with execute_script() but this JavaScript::click() defeats the purpose of the test. First because it doesn't generate all the events like a real click (focus, blur, mousedown, mouseup...) and second because it doesn't guarantee that a real user can interact with the element. But to get rid from this issues you can consider it as an alternate solution.
driver.execute_script("arguments[0].click()", button)
Note:- Before using these options make sure you're trying to interact with correct element using with correct locator, otherwise WebElement.click() would work well after wait until element visible and clickable using WebDriverWait.
Try using an ActionChains:
from selenium.webdriver.common.action_chains import ActionChains
# Your existing code here
# Minus the `button.click()` line
ActionChains(driver).move_to_element(button).click().perform()
I have used this technique when I need to click on a <div> or a <span> element, rather than an actual button or link.
I have a HTML code like this:
<div class="links nopreview"><span><a class="csiAction"
href="/WebAccess/home.html#URL=centric://REFLECTION/INSTANCE/_CS_Data/null">Home</a></span> • <span><span><a class="csiAction"
href="/WebAccess/home.html#URL=centric://SITEADMIN/_CS_Site">Setup</a></span> • </span><span><a
title="Sign Out" class="csiAction csiActionLink">Sign Out</a></span></div>
I would like to click on the link that has the text Home. As this Home link appears after login, I have a code like this:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import re
browser = webdriver.Firefox() # Get local session of firefox
browser.get("http://myServer/WebAccess/login.html") # Load App page
elem = browser.find_element_by_name("LoginID") # Find the Login box
elem.send_keys("Administrator")
elem = browser.find_element_by_name("Password") # Find the Password box
elem.send_keys("Administrator" + Keys.RETURN)
#try:
elem = browser.find_element_by_link_text("Home")
elem.click()
The part till login works great. However the last but one line is problematic
elem = browser.find_element_by_link_text("Home")
It raises this NoSuchElementException where the Home link is there as you can see from the HTML code.
raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: u'Unable to locate element: {"method":"link text","selector":"Home"}'
Any guidance as to what I am doing wrong, please?
Have you tried adding an implicit wait to this so that it waits instead of running to quickly.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import re
browser = webdriver.Firefox() # Get local session of firefox
browser.implicitly_wait(10) #wait 10 seconds when doing a find_element before carrying on
browser.get("http://myServer/WebAccess/login.html") # Load App page
elem = browser.find_element_by_name("LoginID") # Find the Login box
elem.send_keys("Administrator")
elem = browser.find_element_by_name("Password") # Find the Password box
elem.send_keys("Administrator" + Keys.RETURN)
#try:
elem = browser.find_element_by_link_text("Home")
elem.click()
The implicitly_wait call makes the browser poll until the item is on the page and visible to be interacted with.
The most common issues with NoSuchElementException while the element is there are:
the element is in different window/frame, so you've to switch to it first,
your page is not loaded or your method of page load is not reliable.
Solution could include:
check if you're using the right frame/window by: driver.window_handles,
write a wait wrapper to wait for an element to appear,
try XPath instead, like: driver.find_element_by_xpath(u'//a[text()="Foo"]').click(),
use pdb to diagnose your problem more efficiently.
See also: How to find_element_by_link_text while having: NoSuchElement Exception?
Maybe the element you are looking for doesn't exactly match that text string?
I know it can be tricky if it looks like it does on-screen, but sometimes there are oddities embedded like this simple markup "Home" or "Home" which makes the first char italic:
"<i>H</i>ome" is visually identical to "<em>H</em>ome" but does not match text.
Edit: after writing the above answer, I studied the question closer and discovered the HTML sample does show "Home" in plain text, but was not visible due to long lines not wrapping. So I edited the OP to wrap the line for readability.
New observation: I noticed that the Logout element has a "title" attribute, but the Home link element lacks such--try giving it one and using that.
Try adding an implicit wait to this in order to wait, instead of running too quickly.
Or
else you can import time and use time.sleep(25)