1

I use a simple webdriver phantomjs script to update some adverts on preloved.co.uk. This script worked great until recently, but then started failing with the "Click submitted but load failed" error after the login link was clicked. In accordance with this I updated my version of phantomjs to latest stable, 1.9.7 following the guide here. However, now the login click does not seem to register either, and the page does not reload.

The first step is simply getting to login form page.

from selenium import webdriver
br = webdriver.PhantomJS(service_log_path='/path/to/logfile.log')
url = "http://www.preloved.co.uk"
br.get(url)

# Go to login page
login_button = br.find_element_by_xpath('//div[@id="header-status-login"]/a')
login_button.click()

Normally (and if you replace the browser line with br = webdriver.Firefox() for example), this results in reloading to login page, and the script proceeds from there, but now it appears the click does not load the new page at all and br.current_url is still 'http://www.preloved.co.uk/'

Why doesn't this load work?

Even if I extract the href and do an explicit GET it doesn't seem to follow and reload:

newurl=login_button.get_attribute('href')
br.get(newurl)

br.current_url is still 'http://www.preloved.co.uk/'.

Community
  • 1
  • 1
fpghost
  • 2,834
  • 4
  • 32
  • 61

1 Answers1

3

The login page is secured through https. Recently the POODLE vulnerability forced websites to move away from SSLv3 for https, but since PhantomJS uses SSLv3 per default the login page doesn't load. See also this answer.

This can be fixed by passing --ssl-protocol=tlsv1 or --ssl-protocol=any to PhantomJS or upgrading PhantomJS to at least version 1.9.8. It seems that the service_args argument could be used for that in the python bindings for Selenium.

It looks like in the current official implementation the service_args cannot be passed from WebDriver to the Service in PhantomJS. You can sub-class it.

from selenium import webdriver
from selenium.webdriver.phantomjs.service import Service
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver

class PhantomJSService(webdriver.PhantomJS):
    def __init__(self, executable_path="phantomjs", port=0,
                 desired_capabilities=DesiredCapabilities.PHANTOMJS,
                 service_args=None, service_log_path=None):

        self.service = Service(executable_path, 
                               port=port, service_args=service_args,
                               log_path=service_log_path)
        self.service.start()

        try:
            RemoteWebDriver.__init__(self,
                command_executor=self.service.service_url,
                desired_capabilities=desired_capabilities)
        except:
            self.quit()
            raise 

It seems that this webdriver fork contains the necessary arguments to set those options.

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • I see, thanks! Could you say some more about how I would implement this monkey patch in my little script above... – fpghost Oct 25 '14 at 09:57
  • I added the sub-class not monkey patch. I see now that you use `service_log_path`. Does it log correctly? – Artjom B. Oct 25 '14 at 10:24
  • Firstly, ` br = PhantomJSService(service_args=['--ssl-protocol=any',])` works great with the subclass, so thanks for that. As for logging, I'm not quite sure what to do with `service_log_path` now as passing it as an arg to `PhantomJSService` fails with unexpected keyword, and passing it in the list of service_args also fails with `cannot connect to GhostDriver` – fpghost Oct 25 '14 at 11:00
  • Adding `service_log_path=None` to your `__init__` args, and `log_path` to `self.service = Service(executable_path, port=port, service_args=service_args, log_path=service_log_path)` seemed to work – fpghost Oct 25 '14 at 11:19
  • Feel free to edit my answer with this addition. I will approve as soon as I see it. – Artjom B. Oct 25 '14 at 11:23
  • May be a silly question but I'm confused, looking at the source, where exactly is the parent class `webdriver.PhantomJS`?. I can see the module phantomjs, but struggling to see the class PhantomJS – fpghost Oct 25 '14 at 11:31
  • 1
    This should solve the mystery it is just renamed in an `__init__.py`: http://selenium.googlecode.com/svn/trunk/py/selenium/webdriver/__init__.py – Artjom B. Oct 25 '14 at 11:33
  • Broken link - now on github - https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/__init__.py#L27 – Hayden Crocker Aug 29 '16 at 18:24