问题
I am using python + selenium webdriver to automatize checks. I am stuck on websites that request http authentication through popup window.
I am trying to use the "authenticate" method through the following code :
#init.
driver = webdriver.Firefox()
driver.get(url)
#get to the auth popup window by clicking relevant link
elem = driver.find_element_by_id("login_link")
elem.click()
#use authenticate alert method
driver._switch_to.alert.authenticate("login", "password")
the (scarce) infos/doc related to this method indicates that it should submit the credentials provided & validate http auth. It doesn't and I am getting the following error :
File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/common/alert.py", line 105, in authenticate self.driver.execute(Command.SET_ALERT_CREDENTIALS, {'username':username, 'password':password}) File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 201, in execute self.error_handler.check_response(response) File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 159, in check_response raise exception_class(value) selenium.common.exceptions.WebDriverException: Message: Unrecognized command: POST /session/c30d03e1-3835-42f5-ace0-968aef486b36/alert/credentials
is there something I am missing here / has anybody come accross the same issue and resolved it ?
PS : the http://username:password@url trick doesn't work for me in my tests conditions.
回答1:
Basic authentication is pretty easy to work around for automated testing, without having to deal with native alerts/dialogs or other browser differences.
The approach I've used very successfully in the Java world is to set up a Browsermob proxy server in code and register a RequestInterceptor
to intercept all incoming requests (that match the host / URL pattern in question). When you have a request that would otherwise need Basic auth, add an Authorization
HTTP header with the credentials required ('Basic ' + the Base64-encoded 'user:pass' string. So for 'foo:bar' you'd set the value Basic Zm9vOmJhcg==
)
Start the server, set it as a web proxy for Selenium traffic, and when a request is made that requires authentication, the proxy will add the header, the browser will see it, verify the credentials, and not need to pop up the dialog.
Although the technique might seem laborious, by having the header set automatically for every request, you don't have to explicitly add user:pass@
to any URL that might need it, where there are multiple ways into the auth-ed area. Also, unlike user:pass@
users, you don't have to worry about the browser caching (or ceasing to cache, after a certain amount of time) the header, or about crossing HTTP/HTTPS.
That technique works very well, but how to achieve this in Python?
You could use this Python wrapper for Browsermob, which exposes its REST API in Python. This is the REST call you'll need:
POST /proxy/[port]/headers - Set and override HTTP Request headers. For example setting a custom User-Agent. Payload data should be json encoded set of headers (not url-encoded)
So, from the earlier example (pseudocode):
POST localhost:8787/proxy/<proxy_port>/headers '{"Authorization": "Basic Zm9vOmJhcg=="}'
Alternatively, you could see this answer for a custom Python proxy server using Twisted.
回答2:
Basic authentication is possible in the URL, but you'll have to set a preference:
from selenium import webdriver
profile = webdriver.FirefoxProfile()
profile.set_preference("network.http.phishy-userpass-length", 255)
driver = webdriver.Firefox(profile)
driver.get("http://admin:admin@the-internet.herokuapp.com/basic_auth")
If it doesn't work in your case, then it is not basic authentication.
来源:https://stackoverflow.com/questions/35004026/python-selenium-webdriver-using-authenticate-method