Shadow DOM阻止Selenium查找任何元素,包括iframe



我正试图创建一个脚本来提取和输入安全网页上的一些信息,但看起来我在页面上找不到任何元素。每个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 

要定位并切换到.frame((,理想情况下,您需要诱导WebDriverWait等待帧可用并切换到它,您可以使用以下定位器策略之一

  • 使用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']")))
    
  • 使用XPATH:

    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

最新更新