Selenium と Python を使用して「WebDriverException: Message: TypeError: can,t access Dead object」に対処し、フレームが利用可能になるのを待つ方法

okwaves2024-01-25  8

ネストされたフレームを含む、テストする必要があるかなり複雑な Web ページ設定があります。

実際の問題では、Selenium コードは、切り替えたいフレームを含む新しい Web ページ コンテンツをロードしています。明示的な待機を避けるために、次のコード スニペットを試してみました。

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 はフレーム内でフレームを見つけて、それに切り替えることができます。エラーの場合、「frame2」がまだロードされていないときに Selenium が「frame1」に切り替わりますが、「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」の中にあります。

フレームを含む HTML を追加できますか?

– スーツ

2017 年 12 月 14 日 11:26

@suit: それは不可能でしょう...

– アレックス

2017 年 12 月 14 日 12:35

HTML の一部をコピーしてみますが、どうすれば簡単にコピーできるかわかりません...

– アレックス

2017 年 12 月 14 日 15:14



------------------------

ベットer のアプローチは、独自の 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 を見る必要があります。

2

これは私のアプローチに似ていますが、一貫した名前でまとめられています。それは気に入っています...

– アレックス

2017 年 12 月 14 日 14:26

@アレックス、私は撮りましたEC.* クラスをもう一度見てコードを修正しました

– スーツ

2017 年 12 月 14 日 15:34



------------------------

このエラー メッセージは...

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

...<iframe> 間の切り替え中にエラーが発生したことを意味します。

以下に関する詳細情報:

関連する HTML フレームセットの存在 フレームの存在 ネストされたフレームの階層 フレームロードのシーケンス それぞれの <iframe> 内の JavaScript および AJAX 呼び出しの存在タグ

もっと良い方法で問題を分析するのに役立つはずです。ただし、この時点で、最初は Selenium が常にdefault_cにフォーカスを置くことを言及する価値があります。内容。ここでは、ネストされた <frames> を操作するためのいくつかのアプローチを示します。および <フレームセット>:

フレーム 1 とフレーム 2 の両方が同じレベル、つまり最上位のブラウジング コンテキストの下にある場合、次の操作を行う必要があります。

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

フレーム 2 がフレーム 1 内にネストされている場合、フレーム 1 からフレーム 2 に切り替えるには、次の操作を行う必要があります。

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 とフレーム 3 がフレーム 1 内のフレームセット 23 内にある場合、フレーム 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 を使用したより良いアプローチ

iframe と Frameset を扱うときは、expected_conditions と組み合わせて WebDriverWait を誘導する必要があります。

frame_to_be_available_and_switch_to_it()

トップレベルのブラウジングコンテキストから<iframに切り替える例として例>有効なコード行は次のようになります。

フレーム 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 を処理する方法

2

WebDriverWait を含むすべてを試しました。これにより、同じエラーが発生します (つまり、WebDriverWait を使用する質問を参照してください...)

– アレックス

2017 年 12 月 14 日 15:23

DebanjanB: HTML DOM、フレームセット、フレームの読み込み、JavaScript との対話、AJAX 呼び出しなどについて詳しく説明したドキュメントや本をご存知ですか?

– アレックス

2018 年 7 月 5 日 9:51

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。