I would like to download a PDF in Python using Selenium WebDriver. However, for some reason I cannot select / click the download button. It might be due to the fact that the button is not focusable?
This is the button:
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="spinner-third" class="svg-inline--fa fa-spinner-third fa-w-16 fa-icon menubar-h-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M456.433 371.72l-27.79-16.045c-7.192-4.152-10.052-13.136-6.487-20.636 25.82-54.328 23.566-118.602-6.768-171.03-30.265-52.529-84.802-86.621-144.76-91.424C262.35 71.922 256 64.953 256 56.649V24.56c0-9.31 7.916-16.609 17.204-15.96 81.795 5.717 156.412 51.902 197.611 123.408 41.301 71.385 43.99 159.096 8.042 232.792-4.082 8.369-14.361 11.575-22.424 6.92z"></path></svg>
And here is my current code to reproduce:
from selenium import webdriver
import time
website = "https://onlinelibrary.wiley.com/doi/epdf/10.1111/jofi.12895"
driver = webdriver.Chrome()
driver.get(website)
driver.set_window_size(1024, 768)
time.sleep(4)
As the the desired element is within an <iframe> so to invoke click() on the element you have to:
Induce WebDriverWait for the desired frame_to_be_available_and_switch_to_it().
Induce WebDriverWait for the desired element_to_be_clickable().
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe.rc-reader-frame")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "menu-button.download span"))).click()
Using XPATH:
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[#class='rc-reader-frame']")))
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//menu-button[#class='download']//span[text()='PDF']"))).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
Browser snapshot:
Reference
You can find a couple of relevant discussions in:
Switch to an iframe through Selenium and python
Ways to deal with #document under iframe
Related
I'm using selenium to automate some tasks with webdriver.
Turns out I can't find a div to click on, selenium just can't find it.
Does anyone have a suggestion?
HTML :
<div aria-controls="leftAdvPnl_body" aria-expanded="false" aria-haspopup="true" class="rich-stglpanel-header " id="leftAdvPnl_header" onclick="SimpleTogglePanelManager.toggleOnClient(event,'leftAdvPnl');" onkeypress="return keypressclickhandle(event);" role="link" tabindex="0"><div aria-hidden="true" class="rich-stglpanel-marker"><div class="rich-stglpnl-marker" aria-hidden="true" id="leftAdvPnl_switch_on" style="display: none">«</div><div class="rich-stglpnl-marker" aria-hidden="true" id="leftAdvPnl_switch_off">»</div></div><span id="leftAdvPnl_header_label">Pesquisar</span><span aria-hidden="true"> </span></div>
Code phyton:
while len(navegador.find_elements_by_xpath('//*[#id="leftAdvPnl_header"]')) < 1:
time.sleep(1)
print("Procurando formulário do processo")
link=navegador.find_element_by_xpath("//*[#id="leftAdvPnl_header"]")
link.click()
Thanks!
You have 2 nested double quotes, instead of "//*[#id="leftAdvPnl_header"]" use '//*[#id="leftAdvPnl_header"]'
You need to wait for an element to be clickable, so try:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="leftAdvPnl_header"]'))).click()
To click on the element with text as Pesquisar you can use either of the following Locator Strategies:
Using css_selector:
driver.find_element(By.CSS_SELECTOR, "div.rich-stglpanel-header#leftAdvPnl_header span#leftAdvPnl_header_label").click()
Using xpath:
driver.find_element(By.XPATH, "//span[text()='Pesquisar' and #id='leftAdvPnl_header_label']").click()
Ideally, to click on the element you need 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, "div.rich-stglpanel-header#leftAdvPnl_header span#leftAdvPnl_header_label"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Pesquisar' and #id='leftAdvPnl_header_label']"))).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
Please check in the dev tools (Google chrome) if we have unique entry in HTML DOM or not.
xpath that you should check :
//div[#id='leftAdvPnl_header']
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
If we have 1/1 matching node, Please make sure that :
This div is not under an iframe.
This div is not under a shadow-root.
You should not be on new tab/windows launched by selenium.
Code :
try:
WebDriverWait(navegador, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#id='leftAdvPnl_header']"))).click()
print("Clicked on web element")
except:
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
Updated :
CSS are far more better locator than XPath, please try the below one :
div[onclick^='SimpleTogglePanelManager.toggleOnClient'][onclick*='(event,'][onclick*='leftAdvPnl']
Same way to check if we have 1/1 matching node or not.
To click, there are 4 ways in Selenium.
Code trial 1:
time.sleep(5)
driver.find_element_by_css_selector("div[onclick^='SimpleTogglePanelManager.toggleOnClient'][onclick*='(event,'][onclick*='leftAdvPnl']").click()
Code trial 2:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[onclick^='SimpleTogglePanelManager.toggleOnClient'][onclick*='(event,'][onclick*='leftAdvPnl']"))).click()
Code trial 3:
time.sleep(5)
button = driver.find_element_by_css_selector("div[onclick^='SimpleTogglePanelManager.toggleOnClient'][onclick*='(event,'][onclick*='leftAdvPnl']")
driver.execute_script("arguments[0].click();", button)
Code trial 4 :
time.sleep(5)
button = driver.find_element_by_css_selector("div[onclick^='SimpleTogglePanelManager.toggleOnClient'][onclick*='(event,'][onclick*='leftAdvPnl']")
ActionChains(driver).move_to_element(button).click().perform()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
I am trying to use python, selenium and xpath to grab the text $0.180 in the following block of HTML,
<div class="wlp-values-div">
<span class="wlp-last-price-span">$0.180</span>
This code is deep into a websites HTML and I tried to use the following Xpath to locate it:
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://smallcaps.com.au/stocks/?symbol=AWJ")
time.sleep(3)
webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform()
ele = driver.find_element_by_xpath("//div[#class='wlp-values-div']/span[#class='wlp-last-price-span']")
But I receive the error:
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//div[#class='wlp-values-div']/span[#class='wlp-last-price-span']"}
Any help would be greatly appreciated
The last price field is within nested <iframe> elements so you have to:
Induce WebDriverWait for the parent frame to be available and switch to it.
Induce WebDriverWait for the child frame to be available and switch to it.
Induce WebDriverWait for the desired element to be visible.
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
driver.get('https://smallcaps.com.au/stocks/?symbol=AWJ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "svg[data-name='close']"))).click()
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe#wl-summary")))
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe.wl-quote-frame")))
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.wlp-last-price-span"))).get_attribute("innerHTML"))
driver.quit()
Using XPATH:
driver.get('https://smallcaps.com.au/stocks/?symbol=AWJ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[name()='svg' and #data-name='close']"))).click()
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#id='wl-summary']")))
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[#class='wl-quote-frame']")))
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//span[#class='wlp-last-price-span']"))).get_attribute("innerHTML"))
driver.quit()
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
Console Output:
$0.190
You can find a detailed relevant discussion in How To sign in to Applemusic With Python Using Chrome Driver With Selenium
Reference
You can find a couple of relevant discussions in:
Ways to deal with #document under iframe
Switch to an iframe through Selenium and python
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
<iframe class="wl-summary" id="wl-summary" src="https://cloud.weblink.com.au/clients/smallcaps/summary/summary.aspx?symbol=AWJ&" width="100%" height="25" frameborder="0" scrolling="no" allowtransparency="true" style="height: 1077px;"></iframe>
<iframe class="wl-quote-frame" src="quoteFrame.aspx?symbol=AWJ&" scrolling="no" frameborder="0" height="1" style="height: 177px;"></iframe>
It's in a double nested iframe so you have to switch to it. This also has the appropriate waits instead of using time.sleep() and hoping the elements load. It also clicks the popup to get out of the way and prints the spans text.
wait = WebDriverWait(driver, 10)
driver.get("https://smallcaps.com.au/stocks/?symbol=AWJ")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#tve_editor > div'))).click()
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CLASS_NAME, 'wl-summary')))
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CLASS_NAME, 'wl-quote-frame')))
elem=wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'span.wlp-last-price-span')))
print(elem.text)
Import
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
I want to click the "Akkoord" button but I am unable to do that. I already tried different methods but they are not working. Any help will be appreciated.
one of the codes I tried.
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://www.demorgen.be/nieuws')
time.sleep(20)
driver.find_elements_by_class_name('message-component message-button no-children pg-accept-button')[0].click()
The element Akkoord is within an <iframe> so you have to:
Induce WebDriverWait for the desired frame to be available and switch to it.
Induce WebDriverWait for the desired element to be clickable.
You can use either of the following Locator Strategies:
Using CSS_SELECTOR:
driver.get("https://www.demorgen.be/nieuws")
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe[id^='sp_message_iframe']")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[aria-label='Akkoord']"))).click()
Using XPATH:
driver.get("https://www.demorgen.be/nieuws")
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"//iframe[starts-with(#id, 'sp_message_iframe')]")))
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#aria-label='Akkoord']"))).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
Browser Snapshot:
Reference
You can find a couple of relevant discussions in:
Ways to deal with #document under iframe
Switch to an iframe through Selenium and python
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
use xpath or css
css :
[class="message-component message-button no-children pg-accept-button"]
driver.find_elements_by_css_selector('[class="message-component message-button no-children pg-accept-button"]')[0].click()
xpath:
//*[#class="message-component message-button no-children pg-accept-button"]
driver.find_elements_by_xpath('//*[#class="message-component message-button no-children pg-accept-button"]')[0].click()
find_elements_by_class_name expects single class name as argument thats why its not working as space in class indicates multiple classes.
THe find by class actually uses css under the hood. So if you want to find element having multiple class . You can replace space with '.' (THis works only in python)
driver.find_elements_by_class_name('message-component.message-button.no-children.pg-accept-button')[0].click()
Also
The element is inside iframe
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
frame = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR,
"#sp_message_container_404503 iframe")))
driver.switch_to_frame(frame)
driver.find_element_by_css_selector(
'[class="message-component message-button no-children pg-accept-button"]').click()
I have an "onclick" element in a webpage,
<a href="javascript:void(0)" onclick=
"toIndexHtml('3','http://xxxxxxxxxxx/trade','0')">
<i></i>
<span></span>
trade
</a>
It is shown in the webpage as a button and I want to click on it, I tried to search for it using the following code:
driver.find_element_by_xpath("//a[contains(#onclick,'toIndexHtml')]").click()
WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH,"/html/body/div/ul/li[3]/a"))).click()
Both are not working, please suggest if there is any other ways! Thanks in advance!
P.S.: I am using Chrome WebDriver and Chrome v64.
Your first locator looks perfect and should have worked.
Ideally, to click on the element you need 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, "a[onclick^='toIndexHtml']"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[starts-with(#onclick,'toIndexHtml')]"))).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
i am trying to automate some translation through selenium using this url https://www.deepl.com/translator . However I am unable to click on copy button shown in photo here.red marking on button . Inspecting this reveals this html code
<button tabindex="130" _dl-connected="1" _dl-attr="onClick: $0.doCopy" _dl-attr-type="null">
<svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.2949 15.7893H8.59364C7.36747 15.7893 6.37793 14.7947 6.37793 13.5623V3.22705C6.37793 1.9946 7.36747 1 8.59364 1H16.3164C17.5425 1 18.5321 1.9946 18.5321 3.22705V13.5839C18.5106 14.7947 17.521 15.7893 16.2949 15.7893Z" stroke-miterlimit="10"></path>
<path d="M11.1966 20.9997H3.34478C2.05408 20.9997 1 19.9402 1 18.6429V7.35629C1 6.05898 2.05408 4.99951 3.34478 4.99951H11.1966C12.4873 4.99951 13.5414 6.05898 13.5414 7.35629V18.6645C13.5414 19.9402 12.4873 20.9997 11.1966 20.9997Z" fill="white" stroke-miterlimit="10"></path>
</svg>
</button>
Please guide on how to locate this button using both xpath(what should be tag and attribute to be used here) and one other method say css locator. I would be obliged.
The code I used to try and locate the button is:
cpy_btn = driver.find_elements_by_xpath('//*[#id="dl_translator"]/div[1]/div[4]/div[3]/div[4]/div[1]/button')
And later I used
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "(//button[#tabindex='130'])")))
but both didn't work.
The error message I received is: selenium.common.exceptions.ElementClickInterceptedException: Message: Element <button> is not clickable at point (1177,601) because another element <p> obscures it
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:
driver.get('https://www.deepl.com/translator')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.lmt__target_toolbar__copy > button"))).click()
Using XPATH:
driver.get('https://www.deepl.com/translator')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='lmt__target_toolbar__copy']/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
Browser Snapshot:
You can try 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
Then use :
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "(//textarea)[2]"))).click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='lmt__target_toolbar__copy']/button"))).click()
Whith ActionChains :
from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).move_to_element(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='lmt__target_toolbar__copy']/button")))).click().perform()