Selenium:如何获取HTML页面代码中的影子根元素?

huangapple go评论106阅读模式
英文:

Selenium: how to get element in shadow root of html page code?

问题

我需要使用Selenium获取按钮元素,以连接MetaMask钱包到Polygon网络桥。

我需要找到的按钮如下所示:
Selenium:如何获取HTML页面代码中的影子根元素?

但是,据我了解,该按钮被隐藏在HTML页面的阴影根中。

如果我尝试通过右键单击和“检查”来查找按钮的HTML代码,我可以尝试复制它的XPath。
当我粘贴它时是:/button
这不起作用:

metamask = wait.until(EC.element_to_be_clickable((By.XPATH, '/button')))
metamask.click()

会导致错误。这些错误的文本每次都相同,因此我将在最后粘贴它。

如果我尝试右键单击,“检查”并复制CSS选择器,它也不起作用。
复制的CSS选择器是:button:nth-child(1)
我无法使用这个选择器获取按钮。

现在,当我尝试通过CSS选择器或XPath查找按钮时出现的错误文本如下所示:

Traceback (most recent call last):
  File "C:\Users\childoflogos\Desktop\selenium_airdrop_hunter\main.py", line 126, in <module>
    metamask = wait.until(EC.element_to_be_clickable((By.XPATH, '/button')))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\childoflogos\Desktop\selenium_airdrop_hunter\venv\Lib\site-packages\selenium\webdriver\support\wait.py", line 95, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 
Stacktrace:
Backtrace:
    GetHandleVerifier [0x00B9A813+48355]
    (No symbol) [0x00B2C4B1]
    (No symbol) [0x00A35358]
    (No symbol) [0x00A609A5]
    (No symbol) [0x00A60B3B]
    (No symbol) [0x00A8E232]
    (No symbol) [0x00A7A784]
    (No symbol) [0x00A8C922]
    (No symbol) [0x00A7A536]
    (No symbol) [0x00A582DC]
    (No symbol) [0x00A593DD]
    GetHandleVerifier [0x00DFAABD+2539405]
    GetHandleVerifier [0x00E3A78F+2800735]
    GetHandleVerifier [0x00E3456C+2775612]
    GetHandleVerifier [0x00C251E0+616112]
    (No symbol) [0x00B35F8C]
    (No symbol) [0x00B32328]
    (No symbol) [0x00B3240B]
    (No symbol) [0x00B24FF7]
    BaseThreadInitThunk [0x76A100C9+25]
    RtlGetAppContainerNamedObjectPath [0x77D77B4E+286]
    RtlGetAppContainerNamedObjectPath [0x77D77B1E+238]

这是Selenium无法找到和点击元素时常见的错误。

页面HTML代码中的按钮元素(最好尝试自己在HTML代码中定位元素)

我该如何使用Selenium找到并点击此按钮?

更新:
我找到了如何定位阴影根内部元素的信息:

shadow_element = driver.execute_script("return document.querySelector('w3m-modal').shadowRoot.querySelector('div').querySelector('div')")

然而,我仍然无法创建路径到我的目标按钮。
上面的代码在正确的阴影根内到达一个div,但无法捕获在以下HTML注释之后的任何元素:

<!--?lit$702571791$-->

我该如何继续并捕获此注释之后的元素?

英文:

I need to get the element of the button to connect the MetaMask wallet to the polygon network bridge using selenium.

the button I need to find:
Selenium:如何获取HTML页面代码中的影子根元素?
But the button, as I understand it is hidden in shadow root of the html page.

If I find HTML code of the button with right click and 'inspect', I can try to copy it s X-Path.
When I paste it is: /button
That does not work:

metamask = wait.until(EC.element_to_be_clickable((By.XPATH, &#39;/button&#39;)))
metamask.click()

Results in an error. Text of these errors is every time the same so I will paste it in the end.

If I try to right click, 'inspect' and copy CSS-Selector it also does not work.
The CSS-Selector copied is: button:nth-child(1)
I can not get the button with this.

Now, text of the error which arises when I try to find the button by CSS-Selector or X-Path:

Traceback (most recent call last):
  File &quot;C:\Users\childoflogos\Desktop\selenium_airdrop_hunter\main.py&quot;, line 126, in &lt;module&gt;
    metamask = wait.until(EC.element_to_be_clickable((By.XPATH, &#39;/button&#39;)))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File &quot;C:\Users\childoflogos\Desktop\selenium_airdrop_hunter\venv\Lib\site-packages\selenium\webdriver\support\wait.py&quot;, line 95, in until
    raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: 
Stacktrace:
Backtrace:
	GetHandleVerifier [0x00B9A813+48355]
	(No symbol) [0x00B2C4B1]
	(No symbol) [0x00A35358]
	(No symbol) [0x00A609A5]
	(No symbol) [0x00A60B3B]
	(No symbol) [0x00A8E232]
	(No symbol) [0x00A7A784]
	(No symbol) [0x00A8C922]
	(No symbol) [0x00A7A536]
	(No symbol) [0x00A582DC]
	(No symbol) [0x00A593DD]
	GetHandleVerifier [0x00DFAABD+2539405]
	GetHandleVerifier [0x00E3A78F+2800735]
	GetHandleVerifier [0x00E3456C+2775612]
	GetHandleVerifier [0x00C251E0+616112]
	(No symbol) [0x00B35F8C]
	(No symbol) [0x00B32328]
	(No symbol) [0x00B3240B]
	(No symbol) [0x00B24FF7]
	BaseThreadInitThunk [0x76A100C9+25]
	RtlGetAppContainerNamedObjectPath [0x77D77B4E+286]
	RtlGetAppContainerNamedObjectPath [0x77D77B1E+238]

A common error when selenium is unable to find and click an element

Button element in HTML code of the page (better try to locate the element in html code yourself)

How can I find and click this button with selenium?

UPDATE:
I found information on how to locate elements inside shadow root:

shadow_element = driver.execute_script(&quot;return document.querySelector(&#39;w3m-modal&#39;).shadowRoot.querySelector(&#39;div&#39;).querySelector(&#39;div&#39;)&quot;)

Yet still I can not make a path to my target button
Code above reaches one of divs inside of correct shadow root, yet can not grasp any element after following html comment:

&lt;!--?lit$702571791$--&gt;

How do I proceed and grasp elements that go after the comment above?

答案1

得分: 2

你首先需要使用任何策略(XPath、CSS选择器、名称等)找到包含shadow-root的元素。

在你的情况下,这个元素将是标签<w3m-wallet-button name="MetaMask">

导入所需的模块:

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

[更新]:

  • 该网站上的各种元素都嵌套在shadow-root内。
  • 例如,您的目标/所需按钮嵌套在一个5层嵌套的shadow-root内。

以下是完整的工作解决方案:

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

options = ChromeOptions()
options.add_argument("--start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])

driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 10)
url = "https://wallet.polygon.technology/?redirectOnConnect=zkEVM_bridge"

driver.get(url)
# 点击“连接到钱包”按钮
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.navbar__apps-section__auth__login"))).click()
time.sleep(2)
driver.execute_script("""document.querySelector('w3m-modal').shadowRoot.querySelector('w3m-modal-router').shadowRoot.querySelector('w3m-connect-wallet-view').shadowRoot.querySelector('w3m-desktop-wallet-selection').shadowRoot.querySelector('w3m-modal-footer').querySelectorAll('w3m-wallet-button')[0].shadowRoot.querySelector('button').click();""")
time.sleep(5)
  • 在点击<kbd>连接到钱包</kbd>后,我们等待1-2秒,以确保叠加窗口可见,尽管它出现得非常快。
  • 用于定位并点击所需按钮的JavaScript查询
    document.querySelector('w3m-modal').shadowRoot.querySelector('w3m-modal-router').shadowRoot.querySelector('w3m-connect-wallet-view').shadowRoot.querySelector('w3m-desktop-wallet-selection').shadowRoot.querySelector('w3m-modal-footer').querySelectorAll('w3m-wallet-button')[0].shadowRoot.querySelector('button').click();
    

    如果您想要点击第二个或第三个钱包选项,只需在上述JavaScript查询中将querySelectorAll('w3m-wallet-button')[0]分别替换为querySelectorAll('w3m-wallet-button')[1]querySelectorAll('w3m-wallet-button')[2]

Selenium:如何获取HTML页面代码中的影子根元素?

英文:

you first need to locate the element that contains the shadow-root using any strategy (XPath, CSS selector, name, etc).

In your case, this element would be the tag &lt;w3m-wallet-button name=&quot;MetaMask&quot;

shadow_element = driver.find_element(By.CSS_SELECTOR, &#39;w3m-wallet-button[name=&quot;MetaMask&quot;]&#39;).shadow_root

WebDriverWait(shadow_element, 10).until(EC.element_to_be_clickable((By.TAG_NAME, &#39;button&#39;))).click()

Import the required modules:

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

[UPDATE]:

  • Various elements on this website are embedded inside the shadow-root.
  • for example, your target/desired button is embedded in a 5-layer nested shadow-root

Here's the complete working solution:

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

options = ChromeOptions()
options.add_argument(&quot;--start-maximized&quot;)
options.add_experimental_option(&quot;excludeSwitches&quot;, [&quot;enable-automation&quot;])

driver = webdriver.Chrome(options=options)
wait = WebDriverWait(driver, 10)
url = &quot;https://wallet.polygon.technology/?redirectOnConnect=zkEVM_bridge&quot;

driver.get(url)
# click on the &quot;Connect to a Wallet&quot; button
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, &quot;button.navbar__apps-section__auth__login&quot;))).click()
time.sleep(2)
driver.execute_script(&quot;&quot;&quot;document.querySelector(&#39;w3m-modal&#39;).shadowRoot.querySelector(&#39;w3m-modal-router&#39;).shadowRoot.querySelector(&#39;w3m-connect-wallet-view&#39;).shadowRoot.querySelector(&#39;w3m-desktop-wallet-selection&#39;).shadowRoot.querySelector(&#39;w3m-modal-footer&#39;).querySelectorAll(&#39;w3m-wallet-button&#39;)[0].shadowRoot.querySelector(&#39;button&#39;).click();&quot;&quot;&quot;)
time.sleep(5)
  • After clicking on the <kbd>Connect to a Wallet</kbd>, we wait for 1-2 seconds just to make sure that the overlay window is visibly present, although it appears very quickly.
  • The used javascript query to locate and click on the desired button
    document.querySelector(&#39;w3m-modal&#39;).shadowRoot.querySelector(&#39;w3m-modal-router&#39;).shadowRoot.querySelector(&#39;w3m-connect-wallet-view&#39;).shadowRoot.querySelector(&#39;w3m-desktop-wallet-selection&#39;).shadowRoot.querySelector(&#39;w3m-modal-footer&#39;).querySelectorAll(&#39;w3m-wallet-button&#39;)[0].shadowRoot.querySelector(&#39;button&#39;).click();
    

    will click on the very first wallet, if you like to click on the 2nd or 3rd wallet option, just simply replace the querySelectorAll(&#39;w3m-wallet-button&#39;)[0] with querySelectorAll(&#39;w3m-wallet-button&#39;)[1] or querySelectorAll(&#39;w3m-wallet-button&#39;)[2] respectively in the above-mentioned javascript query.

Selenium:如何获取HTML页面代码中的影子根元素?

答案2

得分: 1

<button> 元素位于多个 #shadow-root (open) 内。

Selenium:如何获取HTML页面代码中的影子根元素?

解决方案

要单击带有文本 MetaMask 的按钮,您需要使用 WebDriverWait 来等待 element_to_be_clickable(),您可以使用以下 locator strategy

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((driver.execute_script("return document.querySelector('w3m-connect-wallet-view').shadowRoot.querySelector('w3m-desktop-wallet-selection').shadowRoot.querySelector('w3m-wallet-button').shadowRoot.querySelector('button > div > w3m-text.w3m-sublabel')")))).click()

注意:您必须添加以下导入:

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

The &lt;button&gt; element is within multiple #shadow-root (open)

Selenium:如何获取HTML页面代码中的影子根元素?


Solution

To click on button with text MetaMask you need to induce WebDriverWait for the element_to_be_clickable() and you can use the following locator strategy:

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((driver.execute_script(&quot;return document.querySelector(&#39;w3m-connect-wallet-view&#39;).shadowRoot.querySelector(&#39;w3m-desktop-wallet-selection&#39;).shadowRoot.querySelector(&#39;w3m-wallet-button&#39;).shadowRoot.querySelector(&#39;button &gt; div &gt; w3m-text.w3m-sublabel&#39;)&quot;)))).click()

Note: You have to add the following imports :

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

huangapple
  • 本文由 发表于 2023年7月11日 09:37:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76658230.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定