So I am learning how to use Selenium for web automation - I am trying to write a script that returns my American Express balance to my console. The first step is actually logging on successfully...
It appears that my action for clicking the login button raises an error of not finding the element, even though I can see it when I am on firebug.
This is my code:
from selenium import webdriver
driver = webdriver.Firefox()
baseurl = "https://www.americanexpress.com/canada/"
username = "myusername"
password = "mypassword"
xpaths = { 'usernameField' : "//input[@id='UserID']",
'passwordField' : "//input[@id='Password']",
'submitButton' : "//input[@id='loginButton']"
}
driver.get(baseurl)
driver.find_element_by_xpath(xpaths['usernameField']).clear()
driver.find_element_by_xpath(xpaths['usernameField']).send_keys(username)
driver.find_element_by_xpath(xpaths['passwordField']).clear()
driver.find_element_by_xpath(xpaths['passwordField']).send_keys(password)
driver.find_element_by_xpath(xpaths['submitButton']).click()
This is the console error message I get, where the browser has filled in my login details, but just has not clicked on the login button:
Traceback (most recent call last):
File "get_balance.py", line 29, in <module>
driver.find_element_by_xpath(xpaths['submitButton']).click()
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 232, in find_element_by_xpath
return self.find_element(by=By.XPATH, value=xpath)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 664, in find_element
{'using': by, 'value': value})['value']
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 175, in execute
self.error_handler.check_response(response)
File "/Library/Python/2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 166, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {"method":"xpath","selector":"//input[@id='loginButton']"}
Stacktrace:
at FirefoxDriver.prototype.findElementInternal_ (file:///var/folders/mx/dbnsd72j05zd4k2cls4cvmf00000gn/T/tmpKQDaey/extensions/[email protected]/components/driver-component.js:10271)
at FirefoxDriver.prototype.findElement (file:///var/folders/mx/dbnsd72j05zd4k2cls4cvmf00000gn/T/tmpKQDaey/extensions/[email protected]/components/driver-component.js:10280)
at DelayedCommand.prototype.executeInternal_/h (file:///var/folders/mx/dbnsd72j05zd4k2cls4cvmf00000gn/T/tmpKQDaey/extensions/[email protected]/components/command-processor.js:12274)
at DelayedCommand.prototype.executeInternal_ (file:///var/folders/mx/dbnsd72j05zd4k2cls4cvmf00000gn/T/tmpKQDaey/extensions/[email protected]/components/command-processor.js:12279)
at DelayedCommand.prototype.execute/< (file:///var/folders/mx/dbnsd72j05zd4k2cls4cvmf00000gn/T/tmpKQDaey/extensions/[email protected]/components/command-processor.js:12221)
Any thoughts? Any advice/help is much appreciated, thanks!
This is an a
element, not an input
:
<a tabindex="0" href="#" id="loginButton" title="Login securely">
<span></span>
Log In
</a>
Change your xpath to: //a[@id="loginButton"]
.
Aside from that, for id
attributes there is a find_element_by_id()
method:
driver.find_element_by_id("loginButton").click()
Also, if you want to have element locators separated from the actual "action" code, you can configure it the following way (left a single xpath expression for a sake of an example):
from selenium.webdriver.common.by import By
locators = {
'usernameField': (By.ID, "UserID"),
'passwordField': (By.XPATH, "//input[@id='Password']"),
'submitButton': (By.ID, "loginButton")
}
Then, your "action" code would be using find_element()
:
username = driver.find_element(*locators['usernameField'])
username.clear()
username.send_keys(username)
password = driver.find_element(*locators['passwordField'])
password.clear()
password.send_keys(password)
login_button = driver.find_element(*locators['submitButton'])
login_button.click()