我正在尝试使用 Selenium 单击登录按钮,但不知何故它不起作用。我检查了其他存储库以及以前的线程,但找不到解决方案。这是我的代码:
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
问题是因为它使用
shadow-root
来保护某些元素免受其他元素的意外更改。它允许制作 templates
和 slots
- Web 开发人员的工作可能会更简单。
但是在网页抓取期间访问这些元素会出现问题。
您已经找出哪些元素使用了
shadow-root
(您可以在 Chrome/Firefox 中的 HTML
中的 DevTools
中看到它)并使用 find_element(...).shadow_root.find_element(...)
我发现所有带有
shadow-root
的元素在我开始检查哪个元素需要使用 .shadow_root
- 所以最后我创建了这样的东西:
(对我有用)
def get_item(driver, selector, shadow=True):
print('##### selector:', selector, shadow)
item = driver.find_element(*selector)
for child in item.find_elements(By.CSS_SELECTOR, '*'):
print(f'child: <{child.tag_name}>')
if shadow:
print('!!! 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)
因为在函数中
get_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)
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, "button")
)
item.click()
except Exception as ex:
print("Exception", ex)