Reputation: 35
I am trying to create a simple script with Selenium in Python to do the following: once the IP changes in my server, it will go straight into my account, and update the server's IP with the new one. So far so good. I am able to do everything until I get to the last step. Let me show you my code so far:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import os
cwd = os.path.dirname(os.path.realpath(__file__))
d = webdriver.Chrome(cwd + '/chromedriver')
d.get("https://www.noip.com/login")
IP = '11.11.11.11'
username = d.find_element_by_name('username')
username.send_keys('myusername')
password = d.find_element_by_name('password')
password.send_keys('mypassword')
login = d.find_element_by_name('Login')
login.click()
menu = d.find_element_by_link_text('Dynamic DNS')
menu.click()
vpn_name = d.find_element_by_link_text('myserveraddress.hopto.org')
vpn_name.click()
ipv4_address = d.find_elements_by_name('target')
for i in range(0,15):
ipv4_address[-1].send_keys(Keys.BACKSPACE)
ipv4_address[-1].send_keys(IP)
ipv4_address[-1].send_keys(Keys.ENTER)
d.quit()
Now, when I execute this code LINE BY LINE in my Python IDE, it works like a charm. Note: where it says ipv4_address[-1].send_keys(Keys.BACKSPACE)
it's because there are 2 elements with the name "target" in the tree, so I chose the one I need - basically to delete all the values for the old IP. And it just works fine in the Python IDE when it's ran line by line. But when I run the script altogether it will always return the same error:
<selenium.webdriver.remote.webelement.WebElement (session="56796b375703493c63b9857f5f5e2fdc", element="d13d4ffb-af49-47cf-addc-d0c85e70e1cd")>
Traceback (most recent call last):
File "/Users/jsv/Dropbox/Computer_Science/Python_Scripts/ip_monitor/ip_change.py", line 33, in <module>
ipv4_address[-1].send_keys(Keys.BACKSPACE)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 479, in send_keys
'value': keys_to_typing(value)})
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webelement.py", line 633, in _execute
return self._parent.execute(command, params)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable
My understanding was that the ElementNotInteractableException was an exception that usually arises when obviously the item is not interactable, but in this case it is! I try it line by line and it just works fine!
Does anyone have a clue what is wrong here?
Thanks in advance
Upvotes: 0
Views: 497
Reputation: 5909
I navigated to the page you are testing and noticed an issue. Your selector used here:
ipv4_address = d.find_elements_by_name('target')
is actually locating 2 elements -- one of them is visible, while one of them is not. I believe the first element located is hidden, and the second one is visible. This can be confirmed by checking the is_displayed()
property of each element. This is why your error is getting thrown.
There are a few ways to fix this. The first one is using a lambda expression to filter on the is_displayed()
property of elements in the list:
ipv4_address = d.find_elements_by_name('target')
visible_input = filter(lambda x: x.is_displayed(), ipv4_address)
Or, you can just use list indexing to pick the 2nd element, which is the visible one in this scenario:
ipv4_address = d.find_elements_by_name('target')
visible_input = ipv4_address[1]
I would also invoke WebDriverWait
on the element before interacting with it:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
ipv4_address_elements = WebDriverWait(d, 10).until(EC.presence_of_all_elements_located((By.XPATH, "//input[@name='target']")))
ipv4_address = ipv4_address_elements[1]
Upvotes: 2