如何用Python的Selenium WebDriver处理Firefox无响应问题?

15 投票
3 回答
9217 浏览
提问于 2025-04-17 21:53

我正在用Python和Selenium测试一个网页应用,但Firefox浏览器有时会出现“未响应”的状态。在这个状态下,脚本会停住,直到我手动关闭浏览器。

我尝试了:

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

还有

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

我担心我的问题无法通过waittimeout的方法解决,因为这个页面是用Ajax技术的。.click().submit()方法会发送一个POST请求来回答一个问题,返回的结果是一个字典,通过JavaScript更新页面,显示新的问题。(这是我通过使用Google Chrome开发者工具的网络选项卡Ctrl+Shift+I了解到的)

我的问题是:

我该如何在Selenium中捕捉到Firefox未响应的情况?

我希望能捕捉到这种情况,这样我就可以关闭浏览器并重新打开一个新的。


ExperimentsWithCode的回答后我进行了编辑:
这里有一段我的代码,来说明我的问题。

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

我在一个循环中调用answer_questions()方法。这段代码运行得很好,直到Firefox崩溃,然后就会停住,直到我关闭它。我查看了文档,但我觉得我已经尝试了所有方法。问题不在于加载页面或元素。问题是我不知道如何检测Firefox崩溃的情况。虽然WebDriverWait看起来很有希望,但在Firefox崩溃时并没有抛出TimeoutException

谢谢你的时间。


我想出了一个解决我问题的方法。以下是我所做的代码片段:

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

如果answer_questions()方法在60秒内没有完成,force_timeout()会在一个新线程中运行,并强制关闭firefox.exe。一旦Firefox被终止,代码会抛出一个socket.error错误。捕捉到这个错误后,就可以进行你需要的操作来恢复浏览器崩溃后的状态。我觉得这段代码有点不太优雅,但它正好满足我的需求。
供将来参考:操作系统 - Win8,Selenium版本 - 2.40.0,Firefox版本 - 27.0.1

Windows Taskkill
Python threading.Timer

3 个回答

0

我不知道怎么解释Selenium有时候会变得不响应的情况,但我可以说,退出或者关闭驱动程序(用driver.quit()或者driver.close())并没有什么用,因为控制浏览器的那个对象和进程仍然在运行。

我建议你删除这个对象(用del driver),然后重新创建一个新的驱动程序。

0

对于使用*nix系统的朋友们,

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

这个命令可以很好地结束你当前进程下的Firefox子进程。

pkill的手册页面

1

Webdriver的文档里有一部分专门讲这些内容,你可以在这里找到。

根据文档,你可以试试“显式等待”:

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()

这个方法会在10秒内查找元素,如果找不到就会超时;如果找到了,就会在这个时间内返回这个元素。

撰写回答