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

前端 未结 2 1968
无人共我
无人共我 2020-12-01 23:01

I have a rather complex webpage setup I need to test, containing nested frames.

In the actual problem the selenium code is loading new webpage contents containing a

相关标签:
2条回答
  • 2020-12-01 23:23

    Better approach is to make your own expected_condition. For example:

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

    But maybe there is no need for that.. To tell so I need to see your html DOM.

    0 讨论(0)
  • 2020-12-01 23:27

    This error message...

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

    ...implies that there was an error while switching between <iframes>.

    Some more information in terms of:

    • The relevant HTML
    • Presence of Frameset
    • Presence of Frames
    • Hierarchy of Nested Frames
    • Sequence of Frame Loading
    • Presence of JavaScript and AJAX Calls within the respective <iframe> tags

    would have helped us to analyze the issue in a better way. However, at this point it is worth to mention that initially Selenium always gets the focus on the default_content. Here are a few approaches to work with nested <frames> and <framesets>:

    • If both frame1 and frame2 are at same level i.e. under the Top Level Browsing Context you need to:

      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"))
      
    • If frame2 is nested within frame1, to switch from frame1 to frame2 you need to:

      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"))
      
    • If frame2 and frame3 is within frame1 then, to switch from frame2 to frame3 you need to:

      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"))
      
    • If frame2 and frame3 is within a frameset23 which is within frame1 then, to switch from frame2 to frame3 you need to:

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

    Better approach with proper WebDriverWait

    While dealing with iframe and frameset you need to induce WebDriverWait inconjunction with expected_conditions:

    frame_to_be_available_and_switch_to_it()
    

    As an example to switch from Top Level Browsing Context to an <iframe> an effective line of code will be:

    • Using frame ID:

      WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.ID,"frameID")))
      
    • Using frame NAME:

      WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,"frameNAME")))
      
    • Using frame CLASS_NAME:

      WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.frame_CLASS_NAME,"u_0_f")))
      
    • Using frame CSS_SELECTOR:

      WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"frame_CSS_SELECTOR")))
      
    • Using frame XPATH:

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

    tl; dr

    Ways to deal with #document under iframe

    0 讨论(0)
提交回复
热议问题