切换到 iframe 后无法与其交互 Python/Selenium-wire
Cant interact with iframe after switching to it Python/Selenium-wire
我正在尝试与具有以下结构的页面上的按钮进行交互。感兴趣的按钮位于 iframe 正文中的 div 内,它位于主体内。我已经阅读了有关如何切换到 iframe 的所有 Whosebug 问题 - 正如您在下面看到的那样,我对此没有任何问题。我遇到的问题是,无论该建议如何,我都无法与切换到的 iframe 进行交互。目标是单击特定 iframe 内的按钮。
编辑:这个问题似乎与 selenium-wire 库有关。这是完整的代码。
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import time
url = 'https://sahkovertailu.fi/'
options = {
'suppress_connection_errors': False,
'connection_timeout': None# Show full tracebacks for any connection errors
}
chrome_options = Options()
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument('--auto-open-devtools-for-tabs')
chrome_options.add_argument('--log-level=2')
driver = webdriver.Chrome(ChromeDriverManager().install(), seleniumwire_options=options, chrome_options=chrome_options)
if driver.requests is not None:
del driver.requests
driver.get(url)
iframe = driver.find_element_by_xpath("//iframe[contains(@src, 'privacy')]")
driver.switch_to.frame(iframe)
iframeUniqueId = iframe.get_attribute('cd_frame_id_')
print(iframeUniqueId)
time.sleep(2)
button = driver.find_element_by_xpath("//button[contains(., 'OK')]")
button.click()
这是页面布局的示例
<!doctype html>
<html ng-app="someApp" xmlns="http://www.w3.org/1999/html">
<head>
<script>a lot of scripts</script>
</head>
<body class="unwantedBody">
<iframe> some iframes</iframe>
<div> different divs </div>
<main>
some content
<iframe> multiple iframes on different nested levels </iframe>
</main>
<div> more divs </div>
<script> more scripts </script>
<div id='interesting div'>
<iframe src="uniqueString">
<!doctype html>
#document
<html>
<body>
<div>
<button id='bestButton'>
'Nice title'
</button>
</div>
</body>
</html>
</iframe>
</div>
</body>
</html>
使用 Jupyter Notebook 我已经能够找到 iframe 并切换到它。问题与尝试过快地与 iFrame 交互无关,因为我控制了速度。我试过使用 Expected conditions 并等待 iframe 可以切换到,但这与我的问题无关。
driver.switch_to.default_content # Making sure no other frame is selected
iframe = driver.find_element_by_xpath("//iframe[contains(@src, 'uniqueString')]")
driver.switch_to.frame(iframe)
print(iframe.get_attribute('id'))
上面的代码打印出“interesting div”,所以它成功找到了iframe所在的div并且显然选择了div?当我切换到 iframe 时,网页发生变化,并且为 iframe 提供了一个唯一的 GUID:
<iframe src="uniqueString" cd_frame_id_ = "uniqueGuidThatAlwaysChanges"> ... </iframe>
我可以使用
访问唯一 ID
iframe.get_attribute('cd_frame_id_')
然后我尝试像这样解析 iframe:
bestButton = driver.find_element_by_xpath("//button[@id = 'bestButton']")
bestButton.click()
这给出了错误:
Message: element not interactable
如果我更换上面的驱动。使用 iframe.find_element_by_xpath... 我收到以下错误:
Message: no such element: Unable to locate element:
{"method":"xpath","selector":"//button[@id="bestButton"]"}
我还尝试在 iframe 切换到上面的 switch_to.frame(iframe) 后与 body 进行交互,所以在这个例子中驱动程序已经在iframe:
document = driver.find_element_by_xpath('//html/body')
info = document.get_attribute('class')
print(info)
这会打印出来
unwantedBody
不知何故,驱动程序没有切换到我指定的 iFrame,而是仍然卡在主 HTML 上。在 chrome 上加载网页时,我可以只用这个 XPath //button[contains(@id='bestButton')] 找到我想要的按钮,但在 Selenium 中它不起作用,因为它是拆分的通过 iframe 中的#document。
我错过了什么?如果有帮助,我感兴趣的 iFrame 实际上是关于 cookie 同意的模态 window,我正试图摆脱它以与网站交互。
@qoob,您没有具体说明按钮在网站上的确切位置,google 芬兰语到英语的翻译也不是很好。
因此,我假设您是在谈论第一页本身,因为 iframe 的 DOM 结构看起来与您在问题中提出的问题很相似。如果下图中的按钮是实际的兴趣点,则下面的代码有效。
from selenium import webdriver
import time
driver = webdriver.Chrome(r"C:\chromedriver.exe")
driver.maximize_window()
driver.get("https://sahkovertailu.fi/")
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[@id='sp_message_iframe_204788']"))
time.sleep(2) # remove after testing
driver.find_element_by_xpath("//div[@class='message type-modal']//descendant::button[2]").click()
有关如何使用 XPath 轴的参考,请参考:https://www.lambdatest.com/blog/complete-guide-for-using-xpath-in-selenium-with-examples/#testid2.8.1
请注意 webdriver_manager 目前存在一些问题,因此强烈建议使用 chromedriver/firefox 二进制文件。(https://github.com/SergeyPirogov/webdriver_manager/issues/119)
如果可行,请告诉我!
Akshays 的回答让我找到了正确的方法 - 这个问题可能是使用 ChromeDriver(或至少当前版本 84.0.4147)时 selenium-wire 库中的错误。如果用户对常规 selenium 库有疑问,Akshays 的回答是正确的。 selenium-wire 的问题可以通过使用 Firefox 驱动程序来解决(当前版本的 geckodriver v0.27.0):
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options as chromeOptions
from selenium.webdriver.firefox.options import Options as firefoxOptions
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
if browser == 'chrome':
chrome_options = chromeOptions()
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument('--auto-open-devtools-for-tabs')
chrome_options.add_argument('--log-level=2')
driver = webdriver.Chrome(ChromeDriverManager().install(), seleniumwire_options=options, chrome_options=chrome_options)
elif browser == 'firefox':
firefox_options = firefoxOptions()
firefox_options.headless = True
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install(), seleniumwire_options=options, options=firefox_options)
driver.maximize_window()
编辑: Akshay 的评论实际上更好 - 通过删除 --auto-open-devtools-for-tabs 参数,切换到 iframe 即使在 chrome 驱动程序 selenium-wire webdriver.
Firefox 并非没有问题,例如使用 WebdriverWait 将无法使用自定义等待时间等(似乎只能使用 45 秒,如此处所述 )。
我正在尝试与具有以下结构的页面上的按钮进行交互。感兴趣的按钮位于 iframe 正文中的 div 内,它位于主体内。我已经阅读了有关如何切换到 iframe 的所有 Whosebug 问题 - 正如您在下面看到的那样,我对此没有任何问题。我遇到的问题是,无论该建议如何,我都无法与切换到的 iframe 进行交互。目标是单击特定 iframe 内的按钮。
编辑:这个问题似乎与 selenium-wire 库有关。这是完整的代码。
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import time
url = 'https://sahkovertailu.fi/'
options = {
'suppress_connection_errors': False,
'connection_timeout': None# Show full tracebacks for any connection errors
}
chrome_options = Options()
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument('--auto-open-devtools-for-tabs')
chrome_options.add_argument('--log-level=2')
driver = webdriver.Chrome(ChromeDriverManager().install(), seleniumwire_options=options, chrome_options=chrome_options)
if driver.requests is not None:
del driver.requests
driver.get(url)
iframe = driver.find_element_by_xpath("//iframe[contains(@src, 'privacy')]")
driver.switch_to.frame(iframe)
iframeUniqueId = iframe.get_attribute('cd_frame_id_')
print(iframeUniqueId)
time.sleep(2)
button = driver.find_element_by_xpath("//button[contains(., 'OK')]")
button.click()
这是页面布局的示例
<!doctype html>
<html ng-app="someApp" xmlns="http://www.w3.org/1999/html">
<head>
<script>a lot of scripts</script>
</head>
<body class="unwantedBody">
<iframe> some iframes</iframe>
<div> different divs </div>
<main>
some content
<iframe> multiple iframes on different nested levels </iframe>
</main>
<div> more divs </div>
<script> more scripts </script>
<div id='interesting div'>
<iframe src="uniqueString">
<!doctype html>
#document
<html>
<body>
<div>
<button id='bestButton'>
'Nice title'
</button>
</div>
</body>
</html>
</iframe>
</div>
</body>
</html>
使用 Jupyter Notebook 我已经能够找到 iframe 并切换到它。问题与尝试过快地与 iFrame 交互无关,因为我控制了速度。我试过使用 Expected conditions 并等待 iframe 可以切换到,但这与我的问题无关。
driver.switch_to.default_content # Making sure no other frame is selected
iframe = driver.find_element_by_xpath("//iframe[contains(@src, 'uniqueString')]")
driver.switch_to.frame(iframe)
print(iframe.get_attribute('id'))
上面的代码打印出“interesting div”,所以它成功找到了iframe所在的div并且显然选择了div?当我切换到 iframe 时,网页发生变化,并且为 iframe 提供了一个唯一的 GUID:
<iframe src="uniqueString" cd_frame_id_ = "uniqueGuidThatAlwaysChanges"> ... </iframe>
我可以使用
访问唯一 IDiframe.get_attribute('cd_frame_id_')
然后我尝试像这样解析 iframe:
bestButton = driver.find_element_by_xpath("//button[@id = 'bestButton']")
bestButton.click()
这给出了错误:
Message: element not interactable
如果我更换上面的驱动。使用 iframe.find_element_by_xpath... 我收到以下错误:
Message: no such element: Unable to locate element: {"method":"xpath","selector":"//button[@id="bestButton"]"}
我还尝试在 iframe 切换到上面的 switch_to.frame(iframe) 后与 body 进行交互,所以在这个例子中驱动程序已经在iframe:
document = driver.find_element_by_xpath('//html/body')
info = document.get_attribute('class')
print(info)
这会打印出来
unwantedBody
不知何故,驱动程序没有切换到我指定的 iFrame,而是仍然卡在主 HTML 上。在 chrome 上加载网页时,我可以只用这个 XPath //button[contains(@id='bestButton')] 找到我想要的按钮,但在 Selenium 中它不起作用,因为它是拆分的通过 iframe 中的#document。
我错过了什么?如果有帮助,我感兴趣的 iFrame 实际上是关于 cookie 同意的模态 window,我正试图摆脱它以与网站交互。
@qoob,您没有具体说明按钮在网站上的确切位置,google 芬兰语到英语的翻译也不是很好。 因此,我假设您是在谈论第一页本身,因为 iframe 的 DOM 结构看起来与您在问题中提出的问题很相似。如果下图中的按钮是实际的兴趣点,则下面的代码有效。
from selenium import webdriver
import time
driver = webdriver.Chrome(r"C:\chromedriver.exe")
driver.maximize_window()
driver.get("https://sahkovertailu.fi/")
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[@id='sp_message_iframe_204788']"))
time.sleep(2) # remove after testing
driver.find_element_by_xpath("//div[@class='message type-modal']//descendant::button[2]").click()
有关如何使用 XPath 轴的参考,请参考:https://www.lambdatest.com/blog/complete-guide-for-using-xpath-in-selenium-with-examples/#testid2.8.1
请注意 webdriver_manager 目前存在一些问题,因此强烈建议使用 chromedriver/firefox 二进制文件。(https://github.com/SergeyPirogov/webdriver_manager/issues/119)
如果可行,请告诉我!
Akshays 的回答让我找到了正确的方法 - 这个问题可能是使用 ChromeDriver(或至少当前版本 84.0.4147)时 selenium-wire 库中的错误。如果用户对常规 selenium 库有疑问,Akshays 的回答是正确的。 selenium-wire 的问题可以通过使用 Firefox 驱动程序来解决(当前版本的 geckodriver v0.27.0):
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options as chromeOptions
from selenium.webdriver.firefox.options import Options as firefoxOptions
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
if browser == 'chrome':
chrome_options = chromeOptions()
chrome_options.add_argument("--start-maximized")
chrome_options.add_argument('--auto-open-devtools-for-tabs')
chrome_options.add_argument('--log-level=2')
driver = webdriver.Chrome(ChromeDriverManager().install(), seleniumwire_options=options, chrome_options=chrome_options)
elif browser == 'firefox':
firefox_options = firefoxOptions()
firefox_options.headless = True
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install(), seleniumwire_options=options, options=firefox_options)
driver.maximize_window()
编辑: Akshay 的评论实际上更好 - 通过删除 --auto-open-devtools-for-tabs 参数,切换到 iframe 即使在 chrome 驱动程序 selenium-wire webdriver.
Firefox 并非没有问题,例如使用 WebdriverWait 将无法使用自定义等待时间等(似乎只能使用 45 秒,如此处所述 )。