0

I'm trying to click on the loging button using Selenium, but it's not working somehow. I checked other repos and also previous threads but cannot find the solution. Here is my code:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
class Bot:
 def __init__(self):
 self.driver = webdriver.Chrome()
 def interact(self, selector: str, text: str=None, wait=2, by=By.CSS_SELECTOR):
 element = self.driver.find_element(by=by, value=selector)
 if text is None:
 element.click()
 else:
 element.send_keys(text)
 time.sleep(wait)
class RedditBot(Bot):
 def __init__(self):
 super().__init__()
 self.driver.get("https://www.reddit.com/login/")
if __name__ == "__main__":
 rb = RedditBot()
 rb.interact("input[id='login-username']", text="Brave_Primary1797")
 rb.interact("input[id='login-password']", text="EcOjllIrz3M87q9S08M")
 rb.interact("#login > auth-flow-modal > div.w-100 > faceplate-tracker > button") # this line errors
asked Jun 30, 2024 at 18:30
3
  • what meas "not working"? Do you get error message when you run code in console? If you get error then show it in question (not in comments) as text (not image). Don't expect that we will run code to see problem. We can't see your computer and we can't read in your mind - you have to show all details in question (not in comments) Commented Jul 1, 2024 at 13:01
  • element is in shadow-root which is in another shadow-root,etc. It may need something like find_element('shreddit-async-loader').shadow_root.find_element('auth-flow-login').shadow_root..... Commented Jul 1, 2024 at 14:58
  • Is the issue that the program cant find the button or that its throwing an error? Commented Jul 1, 2024 at 15:12

1 Answer 1

0

Problem is because it uses shadow-root to make some elements protected against accidental changes by other elements. It allows to make templates and slots - and web developer may have simpler work.

But it makes problem to access these elements during web scraping.

You have to find out which elements use shadow-root (you can see it in HTML in DevTools in Chrome/Firefox) and use find_element(...).shadow_root.find_element(...) to get elements inside shadow-root.

I found all elements with shadow-root in DevTools and I started checking which one needs to use .shadow_root - so finally I created something like this to test it manually:

(a it works for me)

def get_item(driver, selector, shadow=True):
 print('[DEBUG] ##### selector:', selector, shadow)
 
 item = driver.find_element(*selector)
 
 for child in item.find_elements(By.CSS_SELECTOR, '*'):
 print(f'[DEBUG] child: <{child.tag_name}>')
 
 if shadow:
 print('[DEBUG] !!! getting shadow root')
 item = item.shadow_root
 
 return item
if __name__ == "__main__":
 try:
 rb = RedditBot()
 time.sleep(2)
 
 rb.interact("input[id='login-username']", text="Brave_Primary1797")
 rb.interact("input[id='login-password']", text="EcOjllIrz3M87q9S08M")
 time.sleep(1)
 
 #rb.interact("#login > auth-flow-modal > div.w-100 > faceplate-tracker > button") # this line errors
 item = rb.driver 
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-overlay-display'))
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-signup-drawer'))
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-drawer'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'div'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-async-loader'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'div'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-slotter'))
 item = get_item(item, (By.CSS_SELECTOR, 'span'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-async-loader'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'auth-flow-login'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-tabpanel'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-form'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'auth-flow-modal'), False)
# item = get_item(item, (By.CSS_SELECTOR, 'div.w-100'), False) # it finds different element
 item = get_item(item, (By.CSS_SELECTOR, 'div[slot]'), False) # OK
# item = get_item(item, (By.CSS_SELECTOR, 'div[slot="primaryButton"]'), False) # OK
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-tracker'), False)
 item = item.find_element(By.CSS_SELECTOR, 'button')
 item.click() 
 
 except Exception as ex:
 print("Exception", ex) 

Because in function get_item() I display children so I could see that I can reduce it to

if __name__ == "__main__":
 try:
 rb = RedditBot()
 time.sleep(2)
 
 rb.interact("input[id='login-username']", text="Brave_Primary1797")
 rb.interact("input[id='login-password']", text="EcOjllIrz3M87q9S08M")
 time.sleep(1)
 
 (
 rb.driver 
 .find_element(By.CSS_SELECTOR, 'shreddit-overlay-display').shadow_root
 .find_element(By.CSS_SELECTOR, 'shreddit-signup-drawer').shadow_root
 .find_element(By.CSS_SELECTOR, 'shreddit-slotter').shadow_root
 .find_element(By.CSS_SELECTOR, "button")
 ).click()
 
 except Exception as ex:
 print("Exception", ex) 

Full code which I was using:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
class Bot:
 def __init__(self):
 self.driver = webdriver.Chrome()
 #self.driver = webdriver.Firefox()
 def interact(self, selector: str, text: str=None, wait=2, by=By.CSS_SELECTOR):
 element = self.driver.find_element(by=by, value=selector)
 if text is None:
 element.click()
 else:
 element.send_keys(text)
 time.sleep(wait)
class RedditBot(Bot):
 def __init__(self):
 super().__init__()
 self.driver.get("https://www.reddit.com/login/")
def get_item(driver, selector, shadow=True, attributes=['id', 'class']):
 print('[DEBUG] ##### selector:', selector, shadow)
 
 item = driver.find_element(*selector)
 
 for attr in attributes:
 print(f'[DEBUG] {attr}:', item.get_attribute(attr))
 
 for child in item.find_elements(By.CSS_SELECTOR, '*'):
 print(f'[DEBUG] child: <{child.tag_name}>')
 
 if shadow:
 print('[DEBUG] !!! getting shadow root')
 item = item.shadow_root
 
 return item
 
def click_button_long_version():
 item = rb.driver 
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-overlay-display'))
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-signup-drawer'))
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-drawer'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'div'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-async-loader'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'div'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-slotter'))
 item = get_item(item, (By.CSS_SELECTOR, 'span'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'shreddit-async-loader'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'auth-flow-login'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-tabpanel'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-form'), False)
 item = get_item(item, (By.CSS_SELECTOR, 'auth-flow-modal'), False)
# item = get_item(item, (By.CSS_SELECTOR, 'div.w-100'), False) # it finds different element
 item = get_item(item, (By.CSS_SELECTOR, 'div[slot]'), False) # OK
# item = get_item(item, (By.CSS_SELECTOR, 'div[slot="primaryButton"]'), False) # OK
 item = get_item(item, (By.CSS_SELECTOR, 'faceplate-tracker'), False)
 item = item.find_element(By.CSS_SELECTOR, 'button')
 item.click()
 
 
def click_button():
 item = (
 rb.driver 
 .find_element(By.CSS_SELECTOR, 'shreddit-overlay-display').shadow_root
 .find_element(By.CSS_SELECTOR, 'shreddit-signup-drawer').shadow_root
 .find_element(By.CSS_SELECTOR, 'shreddit-slotter').shadow_root
 #.find_element(By.CSS_SELECTOR, "#login auth-flow-modal div.w-100 faceplate-tracker button")
 .find_element(By.CSS_SELECTOR, "button")
 #.find_element(By.CSS_SELECTOR, "#login auth-flow-modal div[slot] faceplate-tracker button")
 )
 item.click()
if __name__ == "__main__":
 try:
 rb = RedditBot()
 time.sleep(2)
 
 rb.interact("input[id='login-username']", text="Brave_Primary1797")
 rb.interact("input[id='login-password']", text="EcOjllIrz3M87q9S08M")
 time.sleep(1)
 
 #rb.interact("#login > auth-flow-modal > div.w-100 > faceplate-tracker > button") # this line errors
 click_button_long_version()
 #click_button()
 
 except Exception as ex:
 print("Exception", ex) 
 input("Press ENTER to exit")
answered Jul 1, 2024 at 17:46
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.