如何用Python的Selenium WebDriver处理Firefox无响应问题?
我正在用Python和Selenium测试一个网页应用,但Firefox浏览器有时会出现“未响应”的状态。在这个状态下,脚本会停住,直到我手动关闭浏览器。
我尝试了:
br = webdriver.Firefox()
br.set_page_load_timeout(10)
还有
br = webdriver.Firefox()
br.implicitly_wait(10)
我担心我的问题无法通过wait
或timeout
的方法解决,因为这个页面是用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
3 个回答
我不知道怎么解释Selenium有时候会变得不响应的情况,但我可以说,退出或者关闭驱动程序(用driver.quit()
或者driver.close()
)并没有什么用,因为控制浏览器的那个对象和进程仍然在运行。
我建议你删除这个对象(用del driver
),然后重新创建一个新的驱动程序。
对于使用*nix系统的朋友们,
os.system("pkill -P %d firefox" % os.getpid())
这个命令可以很好地结束你当前进程下的Firefox子进程。
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秒内查找元素,如果找不到就会超时;如果找到了,就会在这个时间内返回这个元素。