1

This is my first time working with Selenium, and I've run into an issue where I can't access an input element that has it's display value set to none.

This is the webpage: https://express.adobe.com/tools/remove-background

The input field is just below the "Browse on your device" button, although it is hidden.

I have tried various ways to access it (By.XPATH, and by ID), but neither work:

file_input = driver.find_element(By.XPATH, "//input[@type='file']")
file_input = driver.find_element("css selector", "#file-input")

This is the error I am getting:

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//input[@type='file']"}
Tory
  • 109
  • 11
  • Have you tried By.ID with 'file-input'? Also, check this answer out https://stackoverflow.com/questions/22110282/how-to-click-on-hidden-element-in-selenium-webdriver – Some Guy May 23 '23 at 20:05

2 Answers2

1

Those are nested within shadow DOMs. You will have to execute Javascript in your Python code to get to the shadow root, and from the root you can traverse your way to the element in question.

Drygord
  • 11
  • 2
  • I saw the #shadow-root and wasn't sure what those were, but I kind of assumed it would be something like an iframe where you have to switch the frame to it. Thanks for your response, I'll look into it further. – Tory May 23 '23 at 20:21
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Blue Robin May 24 '23 at 01:49
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