1

I am trying to access a deeply nested Shadow DOM on the page: https://express.adobe.com/tools/remove-background

Within one of the shadow DOMs is the element I need to access (the file input element).

I am currently trying this:

sptheme = driver.find_element(By.TAG_NAME, "sp-theme")
container = sptheme.find_element(By.ID, "quick-task-container")
shadow_root = container.find_element(By.TAG_NAME, "cclqt-remove-background").shadow_root
sptheme2 = shadow_root.find_element(By.TAG_NAME, "sp-theme")

I get this error due to the 4th line above:

selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid locator

Element Hierarchy (I believe) to the element I wish to access:

  -tag sp-theme
    -id quick-task-container
      -tag cclqt-remove-background
         -SHADOW DOM
           -tag sp-theme
             -tag cclqt-workspace
               -tag cclqt-image-upload
                 -SHADOW DOM
                   -class cclqt-file-upload__container 
                     -this should be where the element is, with the ID: 'file-input'
I.sh.
  • 252
  • 3
  • 13
Tory
  • 109
  • 11
  • just to be clear, is the `` with `id='file-input'` the one you want to locate/select? – Damzaky May 28 '23 at 14:44
  • yep, trying to have the script upload a file to that input – Tory May 28 '23 at 19:18
  • Instead of using a hardcoded path into your DOM tree, it might be more flexible to [*dive* into the DOM](https://stackoverflow.com/questions/71267809/how-to-select-element-tag-from-shadow-root/71269223#71269223) – Danny '365CSI' Engelman May 29 '23 at 10:08

1 Answers1

1

When accessing Shadow DOM there are two main principles:

  1. Find the shadow root element
  2. Using the shadow root as a driver to interact with elements inside it.

First Method

Please note - Since Selenium v4.5 the only supported locator is CSS-Selector

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

# Wait for the shadow root wrapper element to be present
shadow_root_wrapper = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "#quick-task-container > cclqt-remove-background"))
)

# Get the shadow root
shadow_root = shadow_root_wrapper.shadow_root

# Wait for the image upload area element to be visible within the shadow root
image_upload_area = WebDriverWait(shadow_root, 10).until(
    EC.visibility_of_element_located((By.CSS_SELECTOR, "sp-theme > cclqt-workspace > cclqt-image-upload"))
)

# Get the inner shadow root
inner_shadow_root = image_upload_area.shadow_root

# Send an image to the input field
inner_shadow_root.find_element(By.CSS_SELECTOR, "#file-input").send_keys("path_to_image\\file.png")

Second Method

Another approach is to utilize the execute_script() method to execute JavaScript code to interact with the Shadow DOM:

# You should wait for element for smooth execution
shadow_root_script = "return document.querySelector('#quick-task-container > cclqt-remove-background').shadowRoot"
shadow_root = driver.execute_script(shadow_root_script)

image_upload_area = shadow_root.find_element(By.CSS_SELECTOR,"sp-theme > cclqt-workspace > cclqt-image-upload")
inner_shadow_root = image_upload_area.shadow_root

inner_shadow_root.find_element(By.CSS_SELECTOR, "#file-input").send_keys("path_to_image\\file.png")

When handling a complex DOM which envolved many nested Shadow DOMs the best way to find your element path is using the devtools: right click on the element > Copy > Copy js path (example for Chrome)

I.sh.
  • 252
  • 3
  • 13
  • 1
    Error: `selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid locator` Caused by the line: `sptheme2 = shadow_root.find_element(By.TAG_NAME, "sp-theme")` – Tory May 28 '23 at 19:33
  • Apologies for the mistake, apparently Selenium 4.5 doesn't support `TagName` locator for Shadow DOM elements. I've updated the answer – I.sh. May 29 '23 at 11:10
  • I believe the first solution is very close, although it does not work completely. The first solution causes no errors, although nothing happens on the browser after the line `inner_shadow_root.find_element(By.CSS_SELECTOR, "#file-input").send_keys("path_to_image\\file.png")` Successfully uploading the image file to the file input causes the page to start removing the background from the image, which it does not do for some reason. I am at a loss as for why it does nothing, because when clicking on the upload button and manually adding the image, it starts removing the BG from the image. – Tory May 29 '23 at 18:20
  • It works perfectly for me, plz make sure the file **path is correct** - if you're using Windows it should be something like "C:\\Users\\User\\Desktop\\Test.png" and make sure it's the **same image** that works manually. – I.sh. May 29 '23 at 19:04
  • 1
    Oh you are right it does work. I tried a different image this time and it worked, I'm not sure why it didn't work previously as I right clicked the image and clicked "copy path" and used that. Just accepted your answer and awarded the bounty! Thanks for your help! – Tory May 29 '23 at 19:53