Reputation: 5381
Im trying to log into a website using selenium
by doing:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.eco-visio.net/v5/")
username = driver.find_element_by_id("login-username")
username.send_keys("midregcog.admin")
but im getting the following error
ElementNotInteractableException Traceback (most recent call last)
<ipython-input-9-975030640535> in <module>()
8 driver.get("https://www.eco-visio.net/v5/")
9 username = driver.find_element_by_id("login-username")
---> 10 username.send_keys("midregcog.admin")
11
C:\Anaconda2\lib\site-packages\selenium\webdriver\remote\webelement.pyc in send_keys(self, *value)
477 self._execute(Command.SEND_KEYS_TO_ELEMENT,
478 {'text': "".join(keys_to_typing(value)),
--> 479 'value': keys_to_typing(value)})
480
481 # RenderedWebElement Items
C:\Anaconda2\lib\site-packages\selenium\webdriver\remote\webelement.pyc in _execute(self, command, params)
631 params = {}
632 params['id'] = self._id
--> 633 return self._parent.execute(command, params)
634
635 def find_element(self, by=By.ID, value=None):
C:\Anaconda2\lib\site-packages\selenium\webdriver\remote\webdriver.pyc in execute(self, driver_command, params)
319 response = self.command_executor.execute(driver_command, params)
320 if response:
--> 321 self.error_handler.check_response(response)
322 response['value'] = self._unwrap_value(
323 response.get('value', None))
C:\Anaconda2\lib\site-packages\selenium\webdriver\remote\errorhandler.pyc in check_response(self, response)
240 alert_text = value['alert'].get('text')
241 raise exception_class(message, screen, stacktrace, alert_text)
--> 242 raise exception_class(message, screen, stacktrace)
243
244 def _value_or_default(self, obj, key, default):
ElementNotInteractableException: Message: element not interactable
(Session info: chrome=74.0.3729.131)
(Driver info: chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}),platform=Windows NT 10.0.17134 x86_64)
Here is the id tag of the website im trying to get.
Upvotes: 2
Views: 650
Reputation: 5774
As explained here, you need to artificially click the element with javascript since it is being made by javascript itself (selenium cannot "see" the element). Another example of a similar situation is my answer on this question. Adjusting your code like this works (I implemented waits too, but that probably isn't necessary):
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
from selenium.webdriver.common import action_chains
import time
driver = webdriver.Chrome()
driver.get("https://www.eco-visio.net/v5/")
username_element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//form/div/input[@id='login-username']")))# driver.find_element_by_id("login-username")
driver.execute_script("arguments[0].click();", username_element)
time.sleep(1) # give the click a moment to register
action = action_chains.ActionChains(driver)
action.send_keys("midregcog.admin")
action.perform()
This works to fill in the field on my machine! Hope this helps.
@MarcelWilson points out that you just need to wait for the page to load (not entirely sure why since it is , and with a couple tests I'm not sure why it doesn't work with just an explicit wait. Apparently the first answer was overly complicated and you can accomplish the desired effect with:
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
import time
driver = webdriver.Chrome()
driver.get("https://www.eco-visio.net/v5/")
username_element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//form/div/input[@id='login-username']")))# driver.find_element_by_id("login-username")
time.sleep(2) # give a longer wait than the explicit wait in the previous line
username_element.click()
username_element.send_keys("username")
password_element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//form/div/input[@id='login-password'][@type='password']")))# driver.find_element_by_id("login-username")
password_element.click()
password_element.send_keys("password")
I think this may be because in the javascript that generates the page (and I'm no javascript expert) there are lines such as if: loaded()
which leads me to believe that the explicit WebDriverWait
is getting the element, but the javascript is still in the process of loading it in. So the WebDriverWait
makes sure the element exists, and the time.sleep(2)
makes sure it is also loaded before trying to interact with it, at which point it looks like you can interact with it as a normal page without problems. I even got to learn some new stuff for this post XD!
Upvotes: 2
Reputation: 4572
The problem is selenium is trying to interact with the element before it's finished loading in the DOM. One way around this is to use the WebDriverWait in conjunction with the expected_conditions module to "look" for the elements and then interacting with them.
Try something like this.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.get("https://www.eco-visio.net/v5/")
wait = WebDriverWait(driver, 10)
ec = EC.visibility_of_element_located((By.ID, "login-username"))
try:
username = wait.until(ec, f"Could not find {ec.locator}")
username.send_keys("midregcog.admin")
except Exception as exc:
raise
finally:
driver.quit()
Upvotes: 1