Accessing Shadow DOM tree with Selenium
Unfortunately it looks like the webdriver spec does not support this yet.
My snooping uncovered :
http://www.w3.org/TR/webdriver/#switching-to-hosted-shadow-doms
https://groups.google.com/forum/#!msg/selenium-developers/Dad2KZsXNKo/YXH0e6eSHdAJ
What is the correct way to correctly identify an object via Python and Selenium?
econ-button btn btn-primary
are actually 3 class names.By.CLASS_NAME
gets only single class name parameter.
To work with locators containing multiple class names you can use By.XPATH
or By.CSS_SELECTOR
.
As for me both the above methods are good, each of them having several cons and pros.
So, here you can use
browser.find_element(By.CSS_SELECTOR, 'button.econ-button.btn.btn-primary')
Or
browser.find_element(By.XPATH, "//button[@class='econ-button btn btn-primary']")
Generally, you can use By.CSS_SELECTOR
or By.XPATH
. No need to utilize By.ID
or By.CLASS_NAME
since they are actually internally immediately translated to By.CSS_SELECTOR
or By.XPATH
:)
Some people preferring to use By.CSS_SELECTOR
while others prefer By.XPATH
.
As I mentioned previously, each of the above 2 methods having cons and pros.
For example you can locate elements by their texts with XPath only. XPath supports locating parent element based on their child nodes.
On the other hand XPath will not work so good on Firefox driver while it works perfectly on Chrome driver etc.
UPD
The locator for the second nein
radio button can be:
"//label[.//input[@data-econ-property='kreditdaten-beduerfnisfragen-flexibilitaetGewuenscht'][@value='radio3']]"
So, Selenium click can be done with
browser.find_element(By.XPATH, "//label[.//input[@data-econ-property='kreditdaten-beduerfnisfragen-flexibilitaetGewuenscht'][@value='radio3']]").click()
And so on with other buttons
Unable to locate the Sign In element within #shadow-root (open) using Selenium and Python
To Sign In button is deep within multiple #shadow-root (open)
Solution
Tto click()
on the desired element you can use shadowRoot.querySelector()
and you can use the following Locator Strategy:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get('https://developer.servicenow.com/dev.do')
SignInButton = driver.execute_script("return document.querySelector('dps-app').shadowRoot.querySelector('dps-navigation-header').shadowRoot.querySelector('header.dps-navigation-header dps-login').shadowRoot.querySelector('dps-button')")
SignInButton.click()
- Browser Snapshot:
References
You can find a couple of relevant detailed discussions in:
- How to interact with the elements within #shadow-root (open) while Clearing Browsing Data of Chrome Browser using cssSelector
- How to automate shadow DOM elements using selenium?
Related Topics
Python Multiprocessing Linux Windows Difference
Extract Text from Xml Documents in Python
Str' Object Does Not Support Item Assignment
Pandas: Drop a Level from a Multi-Level Column Index
Python: Access Class Property from String
How to Find Length of Digits in an Integer
Testing Whether a Numpy Array Contains a Given Row
How to Use Method Overloading in Python
How to Connect to Tor Browser Using Python
Creating a Dynamic Choice Field
Arranging Text Files Side by Side Using Python
Dictionaries and Default Values
Difference Between Variables Inside and Outside of _Init_()
How to Get a Value of Datetime.Today() in Python That Is "Timezone Aware"
Typeerror: '<=' Not Supported Between Instances of 'Str' and 'Int'