Search code examples
pythonseleniumshadow-domselectors-apiqueryselector

How to access the html nested within multiple shadowRoot using Selenium and Python


I am trying to build a bot to solve Wordle puzzles on the website (https://www.powerlanguage.co.uk/wordle/)

I am using selenium to enter a guess then attempting to inspect the page to see which guesses are correct and incorrect

I can see this information when I inspect the element on chrome but using selenium the html returned is much shorter and points to a javascript app? Is there a way to return the inspect html in selenium? Here is my code.

from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import ElementClickInterceptedException
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

driver = webdriver.Chrome(executable_path=r"/Users/1/Downloads/chromedriver", options=chrome_options)
driver.get("https://www.powerlanguage.co.uk/wordle/")
time.sleep(1)
sends=driver.find_element_by_xpath("/html/body")
sends.click()
sends.send_keys("adieu")
sends.send_keys(Keys.ENTER)
sends.get_attribute('innerHTML')

This is what inner html returns

And this is what I can see on inspection on the website enter image description here


Solution

  • The desired information interms of innerHTML is within multiple #shadow-root (open).

    multiple_shadow_root


    Solution

    To extract the information you need to use shadowRoot.querySelectorAll() and you can use the following Locator Strategy:

    • Code Block:

      driver.get("https://www.powerlanguage.co.uk/wordle/")
      time.sleep(1)
      sends=driver.find_element(By.XPATH, "/html/body")
      sends.click()
      sends.send_keys("adieu")
      sends.send_keys(Keys.ENTER)
      inner_texts = [my_elem.get_attribute("outerHTML") for my_elem in driver.execute_script("""return document.querySelector('game-app').shadowRoot.querySelector('game-row').shadowRoot.querySelectorAll('game-tile[letter]')""")]
      for inner_text in inner_texts:
      print(inner_text)
      
    • Console Output:

      <game-tile letter="a" evaluation="absent" reveal=""></game-tile>
      <game-tile letter="d" evaluation="absent"></game-tile>
      <game-tile letter="i" evaluation="correct"></game-tile>
      <game-tile letter="e" evaluation="absent"></game-tile>
      <game-tile letter="u" evaluation="absent"></game-tile>
      

    References

    You can find a couple of relevant discussions in: