簡體   English   中英

如何解決“WebDriverException: Message: TypeError: can't access dead object”並使用 Selenium 和 Python 等待幀可用

[英]How to address “WebDriverException: Message: TypeError: can't access dead object” and wait for a frame to be available using Selenium and Python

我有一個相當復雜的網頁設置需要測試,其中包含嵌套框架。

在實際問題中,selenium 代碼正在加載包含框架的新網頁內容,我想切換到該框架。 為了避免任何顯式等待,我嘗試了以下代碼片段:

self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).\
        until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).\
        until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))

但是,此代碼段總是失敗並導致以下錯誤:

  ...
  File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/wait.py", line 71, in until
    value = method(self._driver)
  File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 247, in __call__
    self.frame_locator))
  File "/home/adietz/Projects/Venv/nosetests/local/lib/python2.7/site-packages/selenium/webdriver/support/expected_conditions.py", line 402, in _find_element
    raise e
WebDriverException: Message: TypeError: can't access dead object

但是,如果我另外使用睡眠:

time.sleep(30)
self.driver.switch_to_default_content()
WebDriverWait(self.driver, 300).\
        until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame1')))
WebDriverWait(self.driver, 300).\
        until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'frame2')))

selenium 能夠在框架內找到框架並切換到它。 看起來在錯誤情況下 selenium 切換到 'frame1' 而 'frame2' 尚未加載,但 'frame2' 已加載到 'frame1' 的其他實例中,或者 selenium 無法識別(可能是錯誤?)。 所以現在硒在一些“frame1”中,並且由於某些原因沒有意識到“frame2”已被加載。

我可以解決這個問題(不使用長時間睡眠)的唯一方法是使用這段丑陋的代碼:

    mustend = time.time() + 300
    while time.time() < mustend:
        try:
            self.driver.switch_to_default_content()
            self.driver.switch_to.frame(self.driver.find_element_by_id("frame1"))
            self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))               
            break
        except WebDriverException as e:
            self.log("Sleeping 1 sec")
            time.sleep(1)
    if time.time() > mustend:
        raise TimeoutException

因此,每當我收到WebDriverException (死對象)時,我都會轉到頂層框架並嘗試切換到內部框架 - 逐幀。

還有其他方法可以嘗試嗎?

附加信息

  • iframe 是嵌套的,即“frame2”在“frame1”內。

更好的方法是讓你自己的expected_condition。 例如:

class nested_frames_to_be_available_and_switch:
    def __init__(self, *args):
        """
        :param args: locators tuple of nested frames (BY.ID, "ID1"), (BY.ID, "ID2"), ...
        """
        self.locators = args

    def __call__(self, driver):
        try:
            for locator in self.locators:
                driver.switch_to.frame(driver.find_element(*locator))
        except WebDriverException:
            driver.switch_to_default_content()
            return False
        return True

WebDriverWait(driver, 300).until(nested_frames_to_be_available_and_switch((By.ID, 'frame1'), (By.ID, 'frame1')))

但也許沒有必要......說我需要看看你的 html DOM。

這個錯誤信息...

WebDriverException: Message: TypeError: can't access dead object

...暗示在<iframes>之間切換時出現錯誤。

在以下方面的更多信息:

  • 相關的HTML
  • 框架集的存在
  • 幀的存在
  • 嵌套框架的層次結構
  • 幀加載順序
  • 在各自的<iframe>標簽中存在JavaScriptAJAX 調用

會幫助我們以更好的方式分析問題。 然而,在這一點上值得一提的是,最初Selenium總是將焦點放在default_content 上 以下是使用嵌套<frames><framesets>的幾種方法:

  • 如果frame1frame2處於同一級別,即在頂級瀏覽上下文下,您需要:

     self.driver.switch_to.frame(self.driver.find_element_by_id("frame1")) self.driver.switch_to_default_content() self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
  • 如果frame2嵌套在frame1 中,要從frame1切換到frame2,您需要:

     self.driver.switch_to_default_content() self.driver.switch_to.frame(self.driver.find_element_by_id("frame1")) //code self.driver.switch_to.frame(self.driver.find_element_by_id("frame2"))
  • 如果幀2幀3幀1中,然后,切換從幀2到你需要幀3:

     self.driver.switch_to.frame(self.driver.find_element_by_id("frame2")) self.driver.switch_to.frame(self.driver.find_element_by_id("frame1")) self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))
  • 如果幀2幀3frameset23幀1中那么,交換機從幀2幀3中您需要:

     self.driver.switch_to.frame(self.driver.find_element_by_id("frame2")) #ignore presence of frameset23 self.driver.switch_to.frame(self.driver.find_element_by_id("frame1")) #ignore presence of frameset23 self.driver.switch_to.frame(self.driver.find_element_by_id("frame3"))

使用適當的 WebDriverWait 更好的方法

在處理您需要將WebDriverWaitexpected_conditions 結合起來

frame_to_be_available_and_switch_to_it()

作為從頂級瀏覽上下文切換到<iframe>的示例,有效的代碼行將是:

  • 使用ID:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"frameID")))
  • 使用框架名稱:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,"frameNAME")))
  • 使用框架CLASS_NAME:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.frame_CLASS_NAME,"u_0_f")))
  • 使用框架CSS_SELECTOR:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame_CSS_SELECTOR")))
  • 使用框架XPATH:

     WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,"frame_XPATH")))

tl; 博士

iframe下#document的處理方式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM