Delicious
Delicious

Reputation: 967

Handle Firefox Not Responding While Using Selenium WebDriver With Python?

I'm using Selenium with Python to test a web app; however, Firefox will periodically go in the "Not Responding" state. While Firefox is in this state the script will hang until I close it.

I tried:

br = webdriver.Firefox()
br.set_page_load_timeout(10)

and

br = webdriver.Firefox()
br.implicitly_wait(10)

I fear my issue won't be solved by a wait or timeout method since the page is Ajax. The .click() or .submit() method sends a POST to answer a question and the response is a dictionary which via JavaScript updates the page with a new question. (This is what I understand from using the Network tab in Google Chrome Developer Tools Ctrl+Shift+I)

The question is:

How do I catch the Firefox Not Responding situation in Selenium?

I wish to catch this situation so I can close the browser and start a new one.


Edited after ExperimentsWithCode's answer:
Here is a snippet of my code to illustrate my problem.

def answer_questions(self):
    q = QuestionParser(self.br.page_source)
    q.add_to_db()
    qid = q.get_qid()
    # My answer
    my_answer_id = q.get_my_answer()
    self.br.find_element_by_id(my_answer_id).click()
    # Submit answer
    self.br.find_element_by_xpath('//*[contains(@id, "submit_btn_")]').click()
    try:
        find_id = "submit_btn_" + str(qid)
        element = WebDriverWait(self.br,10).until(EC.presence_of_element_located((By.ID, find_id)))
    except:
        print 'I caught you'
    self.rnd(mu=7, s=2) # a method to sleep for a random time

I call the answer_questions() method in a loop. This code runs fine until Firefox crashes then it will hang until I close it. I read the docs and fear I've exhausted everything. The problem is not loading a page or element. The problem is that I don't know how to detect when Firefox crashes. WebDriverWait seemed promising but it did not throw a TimeoutException when Firefox crashed.

Thank you for your time.


I devised a remedy to my problem. Here is a snippet what I did:

import os, socket
from threading import Timer
def force_timeout(self):
    os.system('taskkill /im firefox.exe /f /t')
    # for Windows
    # /im firefox.exe is to select firefox
    # /f is to forcefully kill
    # /t is to kill all child processes

for i in range(0, 1000):
    try:
        t = Timer(60, self.force_timeout)
        # run force_timeout from new thread after 60 seconds
        t.start() # start timer
        self.answer_questions()
        # if self.answer_questions() finishes before 60s, cancel timer
        t.cancel() # cancel timer
    except socket.error:
        self.new_browser() # create a new browser
        self.login()       # login
        self.go_to_questions() # Go to questions page so the loop can continue
        # Code to recover from crash here

If the answer_questions() method does not finish in 60 seconds the force_timeout() will run from a new thread and forcefully kill firefox.exe. Once Firefox is terminated the code will throw a socket.error error. Catch this error then do what you need to do to recover from a browser crashing. I find the code to be a bit dirty but it's working exactly as i need it to.
For future reference: OS - Win8, Selenium Version - 2.40.0, Firefox Version - 27.0.1

Windows Taskkill
Python threading.Timer

Upvotes: 15

Views: 9380

Answers (3)

Oluwaseun Cardoso
Oluwaseun Cardoso

Reputation: 19

I don't know how to explain the often unpredictable unresponsiveness of Selenium, but I can say that quitting or closing the driver (driver.quit() or driver.close() ) doesn't help, because the object and the process that controls the browser is still alive.

I recommend deleting the object (del driver) and re-creating a new driver.

Upvotes: 0

PlasmaSauna
PlasmaSauna

Reputation: 245

For those of you on *nix,

os.system("pkill -P %d firefox" % os.getpid())

works nicely to kill the Firefox children of your current process.

pkill man page

Upvotes: 0

ExperimentsWithCode
ExperimentsWithCode

Reputation: 1184

The Webdriver docs have a section on things like this here.

From the docs, you could try an Explicit Wait:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0

br = webdriver.Firefox()
br.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(br, 10).until(EC.presence_of_element_located((By.ID, "_element_You_Are_Need_To_Load")))
finally:
    br.quit()

This will time out if the element cannot be found in 10 seconds, or return the element within that window.

Upvotes: 1

Related Questions