【问题标题】:Shadow DOM preventing Selenium from finding any elements, including iframesShadow DOM 阻止 Selenium 查找任何元素,包括 iframe
【发布时间】:2022-08-09 04:32:58
【问题描述】:

我正在尝试创建一个脚本来在安全网页上提取和输入一些信息,但看起来我无法在页面上找到任何元素。每个find_element() 调用都会返回NoSuchElementExceptionTimeoutError(意味着WebDriverWait 上的计时器在尝试查找元素时已过期)。

最初我以为这是因为我不在正确的 iframe 上,但我的代码也找不到其中任何一个!在 Chrome 上检查页面后,我能够找到一个父 iframe,然后找到一个我认为不相关的嵌套 iframe。

这个父 iframe 是这样的:

<iframe title=\"Main Page\" id=\"main\" name=\"main\" src=\"super_long_url\" slot=\"core-ui\" style=\"visibility: visible;\"> **Page Content** </iframe>

我尝试过多种方式找到这个 iframe,这里有一些(都是分开的):

WebDriverWait(driver, 60).until(EC.frame_to_be_available_and_switch_to_it(By.ID, \"main\"))

time.sleep(30)
driver.switch_to.frame(By.ID, \"main\")

WebDriverWait(driver, 60).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH,\"//iframe[@title=\'Main Page\']\")))

frames = driver.find_element(By.TAG_NAME, \'iframe\')

WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it(0))

总而言之,我尝试通过 ID、XPATH 甚至索引来定位它。每一次尝试都返回了一个超时错误来自 WebDriverWait (因为它从未找到它)或NoSuchElementException.

我知道这个“主要” iframe 是所有其他 iframe 的父级,但假设它不是,frames = driver.find_element(By.TAG_NAME, \'iframe\') 不应该仍然返回一个元素列表(或至少一个)?

需要明确的是,我不确定这是否只是 iframe 的问题。我认为这可能是 Selenium 无法找到任何元素的问题,包括 iframe。

编辑:几周后,我发现了问题。原来整个页面的元素都在 Shadow DOM 树中。我不得不通过多个嵌套的影子根来 cd (因为没有更好的词),直到我最终可以找到 iframe 并切换到它。这是它在代码形式中的外观。

# First I located the parent div of the entire page
entryPage = driver.find_element(By.CSS_SELECTOR, \"css_selector_name_123\")

# Then I went through through nested shadow roots (shroots)
shroot = entryPage.shadow_root
tempDiv = shroot.find_element(By.CSS_SELECTOR, \"css_selector_name_456\")
shroot2 = tempDiv.shadow_root

# Then I was in the same html directory as the iframe, so I located and switched to it
iframe = shroot2.find_element(By.ID, \"main\")
driver.switch_to.frame(iframe)

# And from here on out, I was able to access all elements on the page just as normal 

    标签: python selenium selenium-webdriver iframe webdriverwait


    【解决方案1】:

    要定位和switch_to.frame(),理想情况下您需要诱导WebDriverWait框架可用并切换到它您可以使用以下任一locator strategies

    • 使用ID

      WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "main")))
      
    • 使用姓名

      WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.NAME, "main")))
      
    • 使用CSS_SELECTOR

      WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe#main[title='Main Page']")))
      
    • 使用路径

      WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "iframe[@id='main' and @title='Main Page']")))
      

    笔记:您必须添加以下导入:

      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.common.by import By
      from selenium.webdriver.support import expected_conditions as EC
    

    【讨论】:

    • 感谢您的快速回复。除非我有误解,否则我已经这样做了。您可以看到使用您发布的 ID 的 WebDriverWait 行与我尝试过的示例中的第一行几乎相同。尽管如此,我尝试了这两个示例并再次获得了 TimeoutException。
    • 我看到你已经更新了你的评论。不幸的是,这些都不适合我。它永远不会找到 iframe 并返回 TimeoutException。我在检查网页时非常清楚地看到了 iframe,但没有弄错。此外,我已经拥有所有这三个确切的进口。
    猜你喜欢
    • 2019-07-08
    • 2015-04-25
    • 1970-01-01
    • 2020-03-16
    • 2021-07-17
    • 1970-01-01
    • 2013-02-25
    • 2016-09-19
    • 2022-12-23
    相关资源
    最近更新 更多