问题1.会打开2个窗口,一个是正常的,一个是data:,
from django.contrib.auth.decorators import login_required
from selenium import webdriver
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.edge.options import Options as EdgeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import TimeoutException, ElementClickInterceptedException
import time
#浏览器配置
class BrowserConfig:
def __init__(self, browser_type='edge', headless=False):
self.browser_type = browser_type.lower()
self.headless = headless
self.options = self._setup_options()
self.driver_path = self._get_driver_path()
def _setup_options(self):
options = {
'chrome': ChromeOptions(),
'edge': EdgeOptions(),
'firefox': FirefoxOptions()
}
if self.browser_type not in options:
raise ValueError(f"Unsupported browser: {self.browser_type}")
if self.headless:
if self.browser_type == 'chrome':
options[self.browser_type].add_argument('--headless=new')
options[self.browser_type].add_argument('--disable-gpu')
elif self.browser_type == 'edge':
options[self.browser_type].add_argument('--headless=chrome')
elif self.browser_type == 'firefox':
options[self.browser_type].add_argument('--headless')
return options[self.browser_type]
def _get_driver_path(self):
driver_paths = {
'edge': r"C:\own\app\python_code\work\入职培训\打印点击\msedgedriver.exe"
}
return driver_paths.get(self.browser_type)
def get_driver(self):
if self.browser_type == 'chrome':
return webdriver.Chrome(options=self.options)
elif self.browser_type == 'edge':
if not self.driver_path:
raise ValueError("Edge driver path is required.")
service = EdgeService(executable_path=self.driver_path)
return webdriver.Edge(service=service, options=self.options)
elif self.browser_type == 'firefox':
return webdriver.Firefox(options=self.options)
else:
raise ValueError(f"Unsupported browser: {self.browser_type}")
#页面元素处理
class ElementActions:
def __init__(self, driver):
self.driver = driver
self.action = ActionChains(driver)
def scroll_to_element(self, element):
try:
self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
time.sleep(0.3)
except Exception as e:
print(f"滚动失败: {e}")
def safe_click(self, element):
try:
element.click()
except ElementClickInterceptedException:
print("元素被遮挡,尝试使用 JavaScript 点击")
self.driver.execute_script("arguments[0].click();", element)
def wait_for_element(self, by, locator, timeout=10):
return WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((by, locator)))
#获取加载后不在父元素下的元素
def get_page_state(self):
return {
"url": self.driver.current_url,
"title": self.driver.title,
"window_handles": len(self.driver.window_handles),
"body_text": self.driver.find_element(By.TAG_NAME, "body").text,
"page_height": self.driver.execute_script("return document.body.scrollHeight;"),
"html_hash": hash(self.driver.find_element(By.TAG_NAME, "html").get_attribute("outerHTML"))
}
def compare_states(self, before, after):
changes = {}
for key in before:
if before[key] != after[key]:
changes[key] = {"before": before[key], "after": after[key]}
return changes
def get_all_button_elements(self):
"""获取当前页面中所有可见的 button 元素"""
script = """
const buttons = Array.from(document.querySelectorAll('button'));
return buttons.filter(btn => {
const style = window.getComputedStyle(btn);
return style.display !== 'none' && style.visibility !== 'hidden';
});
"""
return self.driver.execute_script(script)
def click_and_detect_changes(self, element):
# 记录点击前状态
before_state = self.get_page_state()
before_buttons = self.get_all_button_elements()
# print("点击前页面状态:", before_state)
try:
element.click()
except Exception as e:
print("点击失败:", e)
return []
try:#点击后等待按钮加载
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, 'button'))
)
except TimeoutException:
print("等待按钮加载超时")
time.sleep(1)
after_state = self.get_page_state()
after_buttons = self.get_all_button_elements()
# print("点击后页面状态:", after_state)
changes = self.compare_states(before_state, after_state)
if changes:
print("检测到页面变化:")
# 判断按钮是否是默认展开的
if len(after_buttons) < len(before_buttons):
try:
before_buttons_s = self.get_all_button_elements() # 列表收起时的按钮
element.click()
except Exception as e:
print("点击失败:", e)
return []
after_buttons_1 = self.get_all_button_elements()
new_buttons = list(set(after_buttons_1) - set(before_buttons_s))
try:
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, 'button'))
)
except TimeoutException:
print("等待按钮加载超时")
time.sleep(1)
else:
new_buttons = list(set(after_buttons) - set(before_buttons))
else:
print("页面无变化")
return new_buttons
class Settings_handler():
def __init__(self, browser_config):
self.browser_config = browser_config
self.driver = browser_config.get_driver()
self.element_actions = ElementActions(self.driver)
print(f"Browser {self.browser_config.browser_type} started in "
f"{'headless' if self.browser_config.headless else 'headed'} mode.")
def click_direct_settings_button(self):
try:
settings_button=self.element_actions.wait_for_element(By.XPATH, "//button[contains(text(), 'Settings')]")
self.element_actions.safe_click(settings_button)
# 点击设置下的按钮
new_setting_button = self.element_actions.click_and_detect_changes(settings_button)
if new_setting_button:
print(f"设置菜单下找到 {len(new_setting_button)} 个新增按钮:", new_setting_button)
for btn in new_setting_button:
try:
self.element_actions.safe_click(btn)
print(f"已点击按钮: {btn.text or '未知按钮'}")
time.sleep(0.5)
except Exception as e:
print(f"点击按钮时出错: {str(e)}")
else:
print("未检测到新增按钮")
return True
except TimeoutException:
print("未找到直接可见的设置按钮")
return False
#设置在下拉菜单中
#找到设置
def click_settings_in_dropdowns(self):
# 所有可能展开设置的父元素
parent_elements = self.driver.find_elements(By.XPATH, "//button[@aria-haspopup='true'] | //div[@role='menu']")
for parent in parent_elements:
if not parent.is_displayed() or not parent.is_enabled():
continue
print("尝试点击展开元素")
new_buttons = self.element_actions.click_and_detect_changes(parent)
for btn in new_buttons:
try:
if "setting" in btn.text.lower() or "设置" in btn.text.lower():
print(f"发现设置按钮: {btn.text}")
self.element_actions.safe_click(btn)
#点击设置下的按钮
new_setting_button=self.element_actions.click_and_detect_changes(btn)
if new_setting_button:
print(f"设置菜单下找到 {len(new_setting_button)} 个新增按钮:", new_setting_button)
for btn in new_setting_button:
try:
self.element_actions.safe_click(btn)
print(f"已点击按钮: {btn.text or '未知按钮'}")
time.sleep(0.5)
except Exception as e:
print(f"点击按钮时出错: {str(e)}")
else:
print("未检测到新增按钮")
return True
except Exception:
continue
print("未在下拉菜单中找到设置按钮")
return False
def click_settings_button(self):
#点击设置并点击设置下的可点击的设置
if self.click_direct_settings_button():
return True
# 如果没找到,尝试点击下拉菜单查找设置按钮并点击可点击的设置
if self.click_settings_in_dropdowns():
return True
print("未找到设置按钮")
return False
#页面操作实现
class AutomationWorkflow:
def __init__(self, browser_config, login_url="http://10.244.1.179:3000/"):
self.browser_config = browser_config
self.login_url = login_url
self.driver = browser_config.get_driver()
self.element_actions = ElementActions(self.driver)
self.driver.get(self.login_url)
self.set_cl=Settings_handler(self.browser_config)
print(f"Browser {self.browser_config.browser_type} started in "
f"{'headless' if self.browser_config.headless else 'headed'} mode.")
def login(self, email, password):
try:
email_input = self.element_actions.wait_for_element(By.NAME, 'email')
email_input.send_keys(email)
password_input = self.element_actions.wait_for_element(By.NAME, 'current-password')
password_input.send_keys(password)
login_button = self.driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]')
login_button.click()
time.sleep(1)
return True
except TimeoutException:
print("登录失败,元素未加载或超时")
return False
except Exception as e:
print(f"登录过程中发生错误: {str(e)}")
return False
def logout(self):
try:
user_button = self.element_actions.wait_for_element(
By.XPATH, "//button[@aria-label='User Menu']")
self.element_actions.safe_click(user_button)
logout_button = self.driver.find_element(
By.XPATH, "//div[text()='サインアウト']")
self.element_actions.safe_click(logout_button)
print("登出成功")
except Exception as e:
print(f"登出过程中发生错误: {str(e)}")
def click_all_clickable_elements(self):
try:
elements_locator = (By.CSS_SELECTOR,
'button, a, input[type="button"], input[type="submit"], '
'div[role="button"], div[onclick], [role="menuitem"], '
'[role="option"], [data-testid*="button"], [class*="btn"], '
'[class*="clickable"]')
elements = WebDriverWait(self.driver, 10).until(
EC.presence_of_all_elements_located(elements_locator))
count = len(elements)
print(f"初始找到 {count} 个可能可点击的元素")
original_window = self.driver.current_window_handle
original_url = self.driver.current_url
for index in range(count):
try:
elements = self.driver.find_elements(*elements_locator)
if index >= len(elements):
print(f"元素列表已变化,跳过索引 {index}")
continue
element = elements[index]
self.element_actions.scroll_to_element(element)
if element.is_displayed() and element.is_enabled():
element.click()
print(f"已点击元素 {index + 1}/{count}")
time.sleep(0.5)
try:
alert = WebDriverWait(self.driver, 3).until(
EC.alert_is_present())
print("检测到弹窗,正在处理...")
alert.accept()
except TimeoutException:
print("无弹窗")
time.sleep(0.2)
current_windows = self.driver.window_handles
if len(current_windows) > 1:
for window in current_windows:
if window != original_window:
self.driver.switch_to.window(window)
self.driver.close()
self.driver.switch_to.window(original_window)
else:
if self.driver.current_url != original_url:
self.driver.back()
WebDriverWait(self.driver, 10).until(
EC.presence_of_all_elements_located(elements_locator))
except Exception as e:
print(f"点击元素 {index + 1} 时出错: {str(e)}")
continue
except Exception as e:
print(f"处理可点击元素时出错: {str(e)}")
def handle_input_fields(self, test_value="12"):
try:
input_elements = self.driver.find_elements(By.CSS_SELECTOR,
'input[type="text"], input[type="email"], input[type="number"], '
'input[type="password"], input[type="tel"], input[type="url"], '
'textarea, [role="textbox"], [contenteditable="true"]')
print(f"找到 {len(input_elements)} 个输入框")
original_window = self.driver.current_window_handle
original_url = self.driver.current_url
for index, element in enumerate(input_elements):
try:
self.element_actions.scroll_to_element(element)
element.clear()
element.send_keys(test_value)
print(f"已在输入框 {index + 1} 中输入测试值")
form = element.find_element(By.XPATH, "./ancestor::form[1]")
if form:
submit_buttons = form.find_elements(By.CSS_SELECTOR,
'button[type="submit"], input[type="submit"]')
if submit_buttons:
submit_buttons[0].click()
print(f"已提交输入框 {index + 1} 所在的表单")
time.sleep(1)
current_windows = self.driver.window_handles
if len(current_windows) > 1:
for window in current_windows:
if window != original_window:
self.driver.switch_to.window(window)
self.driver.close()
self.driver.switch_to.window(original_window)
else:
if self.driver.current_url != original_url:
self.driver.back()
time.sleep(2)
except Exception as e:
print(f"处理输入框 {index + 1} 时出错: {str(e)}")
except Exception as e:
print(f"处理输入框时出错: {str(e)}")
def run_automation(self, email, password,login_required=True):
if login_required and self.login_url:
if not self.login(email, password):
print("登陆失败")
return
print("开始自动化操作...")
# self.click_all_clickable_elements()
self.handle_input_fields()
time.sleep(2)
self.set_cl.click_settings_button()
self.logout()
print("自动化操作完成")
time.sleep(3)
self.driver.quit()
if __name__ == "__main__":
login_url = "http://10.244.1.179:3000/"
email = "shengkai.qu@brother-bsh.com.cn"
password = "q123456.+"
login_required=True
browser_config = BrowserConfig(browser_type='edge', headless=False)
automation_workflow = AutomationWorkflow(
browser_config=browser_config, login_url=login_url)
automation_workflow.run_automation(email, password,login_required)