How is it possible to send keys to an editable body in an iframe?
Page:
<iframe id="description_ifr" frameborder="0" allowtransparency="true" title="Rich Text Area..." src="javascript:""" style="width: 100%; height: 200px; display: block;"><html><head>...</head><body id="tinymce" class="mce-content-body " data-id="description" contenteditable="true" spellcheck="false" style="min-height: 184px;"><br data-mce-bogus="1"></body></html></iframe>
Code I tried:
description = browser.find_element_by_id('tinymce')
description.click()
description.send_keys("Test")
Error:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"[id="tinymce"]"}
You should switch to the iframe before sending text.
try,
browser.switch_to_frame(browser.find_element_by_id('description_ifr'))
description = browser.find_element_by_id('tinymce')
description.click()
description.send_keys("Test")
Related
I have a problem with finding element on a webpage. It's a popup window with a confirmation [NO]/[YES]. Selenium can find a parent of a buttons but not a button itself.
Popup window view
HTML block of code:
<div tabindex="-1" role="alertdialog" style="position: fixed; height: auto; width: 300px; top: 188.5px; left: 800px; max-width: 100%;"
class="ui-dialog ui-dialog--notification ui-dialog--modern ui-widget ui-widget-content ui-front ui-dialog-buttons ui-draggable"
aria-describedby="ui-id-3" aria-labelledby="ui-id-4">
<div class="ui-dialog-titlebar ui-corner-all ui-widget-header ui-helper-clearfix ui-draggable-handle"></div>
<div class="ui-dialog-content ui-widget-content" style="width: auto; min-height: 0px; max-height: none; height: 32px;">
<div class="a-AlertMessage">
<div class="a-AlertMessage-body">
<div class="a-AlertMessage-details" id="ui-id-3">Czy chcesz wygenerować pozycje dla całej dostawy?</div>
</div>
</div>
</div>
<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"><div
class="ui-dialog-buttonset">
<button type="button" class="ui-button ui-corner-all ui-widget">Nie</button>
<button type="button" class="js-confirmBtn ui-button ui-corner-all ui-widget ui-button--hot">Tak</button>
</div>
</div>
</div>
Here is a code snippet that selenium can't find and gives an error 'Unable to locate element':
pop_up_yes_button = driver.find_element(By.XPATH, '//*[#id="t_PageBody"]/div[15]/div[3]/div/button[2]').click()
Parent is avaible for selenium without a problem:
driver.find_element(By.XPATH, '//*[#id="t_PageBody"]/div[15]')
I also tried WebDriverWait and ExpectedConditions but it gives TimeoutException:
WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.XPATH, '//*[#id="t_PageBody"]/div[15]/div[3]/div/button[2]'))).click()
As you said that it is a popup window, it is very likely that the button is in an iFrame. You have to wait until the iFrame loads and then search the element again.
Luckily, selenium has a built in function for dealing with iFrames:
your_button = WebDriverWait(driver,
20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,'//*[#id="t_PageBody"]/div[15]/div[3]/div/button[2]')))
your_button.click()
Don't just copy and paste this code, understand this thing and implement it.
Thanks for your time. It's a bit long, really appreciated.
I couldn't locate the element. I tried setting wait, switch frame, executing js
Here is part of the HTML DOM after the page is fully loaded: (the DOM inside iframe is omitted now)
<body class="ng1 nu-theme-neutrino nu-light-theme nu-nav-style-standard nu-responsive-mini nu-responsive-small">
<div id="display" class="flex-centered">
<div class="loading flex-centered" style="min-height: 300px">
<f-icon class="fa-loading icon-xl"></f-icon>
</div>
<iframe style="border: 0px; height: 100%; position: absolute; width: 100%;">#document</iframe>
<div class="prompt legacy-prompt">
<div class="content">
<div class="flex-column-centered">
<p>Enter your credentials</p>
<input id="user" type="text" placeholder="Username">
<input id="pass" type="password" placeholder="Password">
</div>
<div class="button-actions">
<button class="primary" type="button">Login</button>
<button type="button">Close Window</button>
</div>
</div>
</div>
</div>
<script src="/4517d062d20772b8f56b8a652474eaed/js/legacy_theme_setup.js"></script></body>
Here is what I want to achieve in python
ele = driver.find_element(By.CSS_SELECTOR, "#user")
Error:
selenium.common.exceptions.NoSuchElementException: Message: no such element:
Unable to locate element: {"method":"css selector","selector":"#user"}
Then I tried setting wait
ele = WebDriverWait(driver, 60).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#user")))
#or
ele = WebDriverWait(driver, 60).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#user")))
Both got the same output:
[22112:23972:0111/131341.033:ERROR:chrome_browser_main_extra_parts_metrics.cc(227)] START: ReportBluetoothAvailability(). If you don't see the END: message, this is crbug.com/1216328.
[22112:23972:0111/131341.033:ERROR:chrome_browser_main_extra_parts_metrics.cc(230)] END: ReportBluetoothAvailability()
[22112:23972:0111/131341.034:ERROR:chrome_browser_main_extra_parts_metrics.cc(235)] START: GetDefaultBrowser(). If you don't see the END: message, this is crbug.com/1216328.
[22112:1616:0111/131341.059:ERROR:device_event_log_impl.cc(214)] [13:13:41.059] Bluetooth: bluetooth_adapter_winrt.cc:1075 Getting Default Adapter failed.
[22112:23972:0111/131341.131:ERROR:chrome_browser_main_extra_parts_metrics.cc(239)] END: GetDefaultBrowser()
Traceback (most recent call last):
File "C:\Users\a.py", line 60, in <module>
ele = WebDriverWait(driver, 60).until(EC.element_to_be_clickable(
File "C:\Users\...\wait.py", line 89, in until
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException
It says time out, so it didn't find the element within the time limit(60s)
Then I tried locating the element in the browser js console, it succeeded.
document.getElementById('pass')
<input id="pass" type="password" placeholder="Password">
document.getElementById('pass').value = '123456'
'123456'
browser js console screenshot
So I tried executing js
driver.execute_script("document.getElementById('pass').value = '123456'")
Still can't locate
Traceback (most recent call last):
File "C:\Users\a.py", line 54, in <module>
driver.execute_script("document.getElementById('pass').value = '123456'")
...
File "C:\Users\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\selenium\webdriver\remote\errorhandler.py", line 247, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.JavascriptException: Message:
javascript error: Cannot set properties of null (setting 'value')
I also tried to locate the frame, it seems the frame was not loaded properly
DOM inside the iframe:
<html>
<head>
<style>
/* some style */
</style>
</head>
<body style="margin: 0px; padding: 0px; height: 100%; width: 100%; overflow: hidden; cursor: text; user-select: none;">
<x-screen role="textbox" tabindex="-1">
<div
style="display: block; position: fixed; overflow: hidden; user-select: text; width: 342px; height: 864px; left: 0px; top: 0px;">
<x-fold style="display: block; margin-bottom: 0px;"></x-fold>
<x-row>Server closed connection.</x-row>
<x-fold style="display: block;"></x-fold>
</div>
<div style="visibility: hidden; height: 870px;"></div><textarea tabindex="-1" contenteditable="true"></textarea>
</x-screen>
<div class="cursor-node" focus="false" title="(0, 25)"></div>
<div style="position: absolute; top: -99px; display: block; width: 10px; height: 10px;"></div>
</body>
</html>
Code:
ele = WebDriverWait(driver, 15).until(EC.frame_to_be_available_and_switch_to_it(
(By.CSS_SELECTOR, "iframe")))
print("iframe", ele)
#output: iframe True
ele = driver.find_element(By.CSS_SELECTOR, "html")
print("html", ele.get_attribute('innerHTML'))
#output: html <head></head><body></body>
ele = driver.find_element(By.CSS_SELECTOR, "div.cursor-node")
#output:no such element: Unable to locate element: {"method":"css selector","selector":"div.cursor-node"}
ele = driver.find_element(By.CSS_SELECTOR, "#pass")
#output: no such element: Unable to locate element: {"method":"css selector","selector":"#pass"}
driver.switch_to.default_content()
ele = driver.find_element(By.CSS_SELECTOR, "#pass")
#output: no such element: Unable to locate element: {"method":"css selector","selector":"#pass"}
Many thanks!
Try having a look at switch_to_frame, see:
https://selenium-python.readthedocs.io/navigating.html#moving-between-windows-and-frames
iframe = driver.find_element_by_css_selector("iframe")
driver.switch_to_frame(iframe)
elem = driver.find_element_by_css_selector("#user")
As far I can see, there is no need to switch the frame since this element is out of it.
I couldn't validate my idea, since the HTML code you placed isn't interactable.
I've modified the HTML setting up a default value in this item and it's not giving the value, however, I'm able to get the position and others values from this web element. I would advise to remove the switch method and then double check.
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome('chromedriver.exe') # Optional argument, if not specified will search path.
try:
driver.get('C:\\Users\\user\\IdeaProjects\\chrome-selenium-python\\index.html')
time.sleep(2) # Let the user actually see something!
ele = driver.find_element(By.CSS_SELECTOR, "#user")
ele.send_keys("Example")
time.sleep(2)
print("Location", ele.location)
print("Tag", ele.tag_name)
except Exception as a:
print(a)
finally:
driver.quit()
wait=WebDriverWait(driver,30)
wait.until(EC.presence_of_element_located((By.ID,"id"))).send_keys('user')
Try for presence.
Imports:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Thank everyone for answering and trying to help me out!
I used
html = driver.page_source
print(html)
to print and see what is selenium actually seeing, and I found it was another different page. Then I realized this is another browser tab.
So I think it's solved. Thanks for your kind help
I try to scroll a menu with this div in
<div class="N9abW" style="height: 100%; overflow: hidden auto;"><div style="flex-direction: column; padding-bottom: 8640px; padding-top: 0px;">
<div style="flex-direction: column; padding-bottom: 8640px; padding-top: 0px;"><div class=" Igw0E IwRSH eGOV_ ybXk5 _4EzTm pjcA_ iHqQ7 L-sTb ">
My code is this:
area = driver.find_element_by_css_selector('.N9abW')
time.sleep(5)
driver.implicitly_wait(10)
action = ActionChains(driver)
action.move_to_element(area).click().perform()
driver.execute_script("window.scrollBy(0, 1500);", area)
I got no error program exit after code. If someone has a clue or tied same thing. Please help.
driver.execute_script("arguments[0].scrollIntoView();", area)
could you try the above script
area = driver.find_element_by_css_selector('.N9abW')
driver.implicitly_wait(10)
action = ActionChains(driver)
action.move_to_element(area)
print(area)
scrol = driver.execute_script("arguments[0].scrollBy(0,1000)", area)
This fix the issue thank to PDHide
"arguments[0[.scrollBy(0,1000)", area)
I would like to test a patched implementation of juptyerlab. I was hoping to use selenium to execute "hello world" in a code cell. So far I can log in and create a new notebook:
from selenium import webdriver
driver = webdriver.Firefox()
# assume jupyterlab is running and serving on localhost at port 8888
driver.get("http://localhost:8888")
elem = driver.find_element_by_id("password_input")
password = ""
elem.send_keys(password)
elem = driver.find_element_by_id("login_submit")
elem.click()
elem = driver.find_element_by_css_selector(".jp-Launcher-cwd+ .jp-Launcher-section .jp-LauncherCard")
elem.click()
This creates a new notebook, but now I'm stuck at the point of entering some code in a cell and running it. If I view the page source I don't see any html elements for the cells. But if I enter print("test") in a cell, then driver.page_source contains this (it's pretty nested in other stuff I've omitted too):
<div class="CodeMirror cm-s-jupyter CodeMirror-wrap jp-mod-readOnly">
<div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 0px;">
<textarea
style="position: absolute; bottom: -1em; padding: 0px; width: 1px; height: 1em; outline: currentcolor none medium;"
autocorrect="off" autocapitalize="off"
spellcheck="false" tabindex="0"
wrap="off"></textarea></div>
<div class="CodeMirror-vscrollbar" tabindex="-1"
cm-not-content="true"
style="display: block; bottom: 0px;">
<div style="min-width: 1px; height: 33px;"></div>
</div>
<div class="CodeMirror-hscrollbar" tabindex="-1"
cm-not-content="true">
<div style="height: 100%; min-height: 1px; width: 0px;"></div>
</div>
<div class="CodeMirror-scrollbar-filler"
cm-not-content="true"></div>
<div class="CodeMirror-gutter-filler"
cm-not-content="true"></div>
<div class="CodeMirror-scroll" tabindex="-1" draggable="true">
<div class="CodeMirror-sizer"
style="margin-left: 0px; padding-right: 0px; padding-bottom: 0px;">
<div style="position: relative;">
<div class="CodeMirror-lines" role="presentation">
<div style="position: relative; outline: currentcolor none medium;"
role="presentation">
<div class="CodeMirror-measure">
<pre><span>xxxxxxxxxx</span></pre>
</div>
<div class="CodeMirror-measure">
<pre class="CodeMirror-line"
role="presentation"><span
role="presentation"><span
class="cm-builtin">print</span>(<span
class="cm-string">"test"</span>)</span></pre>
</div>
<div style="position: relative; z-index: 1;"></div>
<div class="CodeMirror-cursors"></div>
<div class="CodeMirror-code"
role="presentation"></div>
</div>
</div>
</div>
</div>
<div style="position: absolute; height: 30px; width: 1px; border-bottom: 0px solid transparent;"></div>
<div class="CodeMirror-gutters"
style="display: none;"></div>
</div>
</div>
I can see where the text for print("text") is (i.e. the deepest nested elements in the above html snippet), but I can't figure out which element here I would be able to send text to or send keys to.
I came across robotframework-jupyterlibrary and it has some clues such as this and this . From those links I see
${JLAB CSS ACTIVE INPUT} ${JLAB CSS ACTIVE CELL} .CodeMirror
and
Add and Run JupyterLab Code Cell
[Arguments] ${code}=print("hello world")
[Documentation] Add a ``code`` cell to the currently active notebook and run it.
Click Element css:${JLAB CSS NB TOOLBAR} ${JLAB CSS ICON ADD}
Sleep 0.1s
${cell} = Get WebElement css:${JLAB CSS ACTIVE INPUT}
Click Element ${cell}
Set CodeMirror Value ${JLAB CSS ACTIVE INPUT} ${code}
Run Current JupyterLab Code Cell
Click Element ${cell}
which makes me think if I select the .CodeMirror element, then I just need to figure out what Get WebElement does in that weird language and how to do it in selenium.
Any ideas?
I've also tried (based on https://stackoverflow.com/a/48723135/1011724 and https://stackoverflow.com/a/50279295/1011724):
from selenium.webdriver.common.action_chains import ActionChains
actions = action_chains.ActionChains(driver)
textarea = driver.find_elements_by_css_selector('.CodeMirror textarea')[0] # tried for [0], [1] ,[2] and [3] which is all of them.
actions.move_to_element(textarea).click().send_keys("testing...").perform()
but I keep getting the error
selenium.common.exceptions.WebDriverException: Message: TypeError: rect is undefined
Code below tested with Chrome, Firefox and jupyterlab latest versions:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
driver.get("http://localhost:8888")
token = "0107216930d05db8a7c36ad6a73573dd5349c3dd56fee852"
wait.until(EC.element_to_be_clickable((By.ID, "password_input"))).send_keys(token, Keys.ENTER)
# wait for "Python 3" Notebook menu or CodeMirror element if already launched.
wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "[title='Python 3'][data-category='Notebook'], .jp-Notebook .CodeMirror")))
# if "Python 3" Notebook menu found click to open new Notebook
if len(driver.find_elements_by_css_selector("[title='Python 3'][data-category='Notebook']")) > 0:
driver.find_element_by_css_selector("[title='Python 3'][data-category='Notebook']").click()
# wait for CodeMirror and click to focus
code_mirror = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".jp-Notebook .CodeMirror")))
code_mirror.click()
code_mirror.find_element_by_tag_name("textarea").send_keys("print('Hello World!')")
driver.find_element_by_css_selector("[data-icon='run']").click()
output = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".jp-OutputArea-output")))
print(output.text)
assert output.text.strip() == "Hello World!"
driver.quit()
To Open Jupyter-Notebook:
Either Open a command window and navigate to the repository folder or Open anaconda-command-prompt window and simply execute
jupyter notebook --NotebookApp.token='' --NotebookApp.password=''
After loading notebook using driver.get("http://localhost:8888"), Here is the most tricky part, that how to select a Dynamically changing object. Visit Reference: Dynamically Changing IDs.
By using find_element_by_xpath
By using find_element_by_css_selector
These both will give you the same selection-point but it would be better to use Xpath which is more convenient technique. You can move forward like this;
import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome('chromedriver.exe')
wait = WebDriverWait(driver, 20)
driver.maximize_window()
website_url = "http://localhost:8888/"
driver.get(website_url)
# Using Xpath
# I prefer using xpath, because it is simple to understand
# and if you want to dynamically enter data into fields, it would be an awesome approach
driver.find_element_by_xpath("//div[#id='new-buttons']").click()
if len(driver.find_elements_by_xpath("//div[#id='new-buttons']//li[#id='kernel-python3']")) > 0:
time.sleep(3)
driver.find_element_by_xpath("//div[#id='new-buttons']//li[#id='kernel-python3']").click()
driver.find_element_by_xpath('//div[#class="cell code_cell rendered selected"]').click()
# Using css_selector
#driver.find_element_by_css_selector("#notebook-container > div").click()
command = 'print("Hello World!")'
#a = driver.find_element_by_css_selector("#notebook-container > div > div.input > div.inner_cell >"
# "div.input_area > div > div:nth-child(1) > textarea")
time.sleep(3)
# To select Note-Book text-area and place command in it.
a = driver.find_element_by_xpath('//div[#class="input_area"]//textarea').click().send_keys(command)
# To run the Code in Selected Cell
time.sleep(3)
driver.find_element_by_xpath("//button[#title='Run']").click()
print("Test is done.")
<div class="container-fluid ">
<div class="navbar-header">
<span id="problem_hide_search" class="nav navbar-left">
<span id="ca660735dba5d3003d7e5478dc9619b2_title" class="list_search_title navbar-text " style="float: left; display:inherit">Go to</span>
<div style="float: left; display:inherit">
<div class="input-group" style="width: 300px;">
<span class="input-group-addon input-group-select">
<label class="sr-only" for="ca660735dba5d3003d7e5478dc9619b2_text">Search</label>
<input id="ca660735dba5d3003d7e5478dc9619b2_text" class="form-control" name="ca660735dba5d3003d7e5478dc9619b2_text" style="width: 150px;" placeholder="Search"/>
</div>
</div>
<script data-comment="widget search load event">addLoadEvent(function () { new GlideWidgetSearch('ca660735dba5d3003d7e5478dc9619b2', 'problem', 'true'); });</script>
Am trying to locate the Search box by switching into iframe and selecting by
search_box = driver.find_element_by_xpath('//*#id="ca660735dba5d3003d7e5478dc9619b2_text"]')
But i get error unable to locate Message: no such element: Unable to locate element:
Even thought I find one matching node.
As you mentioned in your question that you are trying to locate the Search box by switching into iframe and selecting as per the best practices you should :
Induce WebDriverWait for the frame to be available to switch as follows :
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it(By.ID,"id_of_iframe"))
Here you will find a detailed discussion How can I select a html element no matter what frame it is in in selenium?
While you look out for an element within an <iframe> tag induce WebDriverWait with proper expected_conditions. Considering the fact that you intend to send text to the element you can use the following line of code :
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='navbar-header']//input[#class='form-control' and contains(#id,'_text')]"))).send_keys("hello")