| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- 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.webdriver.common.keys import Keys
- from selenium.common.exceptions import TimeoutException, NoSuchElementException, ElementNotVisibleException
- import time
- class SeleniumBase:
- def __init__(self, driver):
- """
- 初始化Selenium基础操作类
- :param driver: WebDriver实例
- """
- self.driver = driver
- self.wait = WebDriverWait(self.driver, 10) # 默认等待10秒
- def set_implicit_wait(self, seconds):
- """设置隐式等待时间"""
- self.driver.implicitly_wait(seconds)
- def set_explicit_wait(self, seconds):
- """设置显式等待时间"""
- self.wait = WebDriverWait(self.driver, seconds)
- # ==================== 浏览器操作 ====================
- def open_url(self, url):
- """打开指定URL"""
- self.driver.get(url)
- def get_current_url(self):
- """获取当前URL"""
- return self.driver.current_url
- def get_page_title(self):
- """获取页面标题"""
- return self.driver.title
- def refresh_page(self):
- """刷新页面"""
- self.driver.refresh()
- def navigate_forward(self):
- """浏览器前进"""
- self.driver.forward()
- def navigate_back(self):
- """浏览器后退"""
- self.driver.back()
- def maximize_window(self):
- """最大化窗口"""
- self.driver.maximize_window()
- def set_window_size(self, width, height):
- """设置窗口大小"""
- self.driver.set_window_size(width, height)
- def get_window_size(self):
- """获取窗口大小"""
- return self.driver.get_window_size()
- def switch_to_frame(self, frame_reference):
- """切换到指定frame"""
- self.driver.switch_to.frame(frame_reference)
- def switch_to_default_content(self):
- """切换回默认内容"""
- self.driver.switch_to.default_content()
- def switch_to_window(self, window_handle):
- """切换到指定窗口"""
- self.driver.switch_to.window(window_handle)
- def switch_to_newest_window(self):
- """切换到最新打开的窗口"""
- handles = self.driver.window_handles
- self.driver.switch_to.window(handles[-1])
- return handles[-1]
- def close_current_window(self):
- """关闭当前窗口"""
- self.driver.close()
- def get_all_window_handles(self):
- """获取所有窗口句柄"""
- return self.driver.window_handles
- def get_current_window_handle(self):
- """获取当前窗口句柄"""
- return self.driver.current_window_handle
- def execute_script(self, script, *args):
- """执行JavaScript脚本"""
- return self.driver.execute_script(script, *args)
- def scroll_to_element(self, element):
- """滚动到指定元素"""
- self.execute_script("arguments[0].scrollIntoView();", element)
- def scroll_to_bottom(self):
- """滚动到页面底部"""
- self.execute_script("window.scrollTo(0, document.body.scrollHeight);")
- def scroll_to_top(self):
- """滚动到页面顶部"""
- self.execute_script("window.scrollTo(0, 0);")
- def take_screenshot(self, filename):
- """截取屏幕截图"""
- self.driver.save_screenshot(filename)
- # ==================== 元素定位 ====================
- def find_element(self, by, value, timeout=None):
- """
- 查找元素(带等待)
- :param by: 定位方式 (By.ID, By.XPATH, By.CSS_SELECTOR, etc.)
- :param value: 定位值
- :param timeout: 超时时间,默认使用类初始化时的等待时间
- :return: WebElement
- """
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- try:
- return wait.until(EC.presence_of_element_located((by, value)))
- except TimeoutException:
- raise NoSuchElementException(f"元素未找到: {by}={value}")
- def find_elements(self, by, value, timeout=None):
- """
- 查找多个元素(带等待)
- :param by: 定位方式
- :param value: 定位值
- :param timeout: 超时时间
- :return: 元素列表
- """
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- try:
- return wait.until(EC.presence_of_all_elements_located((by, value)))
- except TimeoutException:
- return []
- def find_visible_element(self, by, value, timeout=None):
- """
- 查找可见元素
- :param by: 定位方式
- :param value: 定位值
- :param timeout: 超时时间
- :return: WebElement
- """
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- try:
- return wait.until(EC.visibility_of_element_located((by, value)))
- except TimeoutException:
- raise ElementNotVisibleException(f"元素不可见: {by}={value}")
- def find_clickable_element(self, by, value, timeout=None):
- """
- 查找可点击元素
- :param by: 定位方式
- :param value: 定位值
- :param timeout: 超时时间
- :return: WebElement
- """
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- try:
- return wait.until(EC.element_to_be_clickable((by, value)))
- except TimeoutException:
- raise ElementNotVisibleException(f"元素不可点击: {by}={value}")
- # 快捷定位方法
- def by_id(self, id_value, timeout=None):
- """通过ID定位元素"""
- return self.find_element(By.ID, id_value, timeout)
- def by_name(self, name_value, timeout=None):
- """通过Name定位元素"""
- return self.find_element(By.NAME, name_value, timeout)
- def by_xpath(self, xpath_value, timeout=None):
- """通过XPath定位元素"""
- return self.find_element(By.XPATH, xpath_value, timeout)
- def by_css(self, css_value, timeout=None):
- """通过CSS选择器定位元素"""
- return self.find_element(By.CSS_SELECTOR, css_value, timeout)
- def by_class(self, class_value, timeout=None):
- """通过Class定位元素"""
- return self.find_element(By.CLASS_NAME, class_value, timeout)
- def by_link_text(self, link_text, timeout=None):
- """通过链接文本定位元素"""
- return self.find_element(By.LINK_TEXT, link_text, timeout)
- def by_partial_link_text(self, partial_link_text, timeout=None):
- """通过部分链接文本定位元素"""
- return self.find_element(By.PARTIAL_LINK_TEXT, partial_link_text, timeout)
- def by_tag(self, tag_name, timeout=None):
- """通过标签名定位元素"""
- return self.find_element(By.TAG_NAME, tag_name, timeout)
- # ==================== 元素操作 ====================
- def click(self, by, value, timeout=None):
- """点击元素"""
- element = self.find_clickable_element(by, value, timeout)
- element.click()
- def input_text(self, by, value, text, timeout=None):
- """输入文本"""
- element = self.find_element(by, value, timeout)
- element.clear()
- element.send_keys(text)
- def clear_text(self, by, value, timeout=None):
- """清除文本"""
- element = self.find_element(by, value, timeout)
- element.clear()
- def get_text(self, by, value, timeout=None):
- """获取元素文本"""
- element = self.find_element(by, value, timeout)
- return element.text
- def get_attribute(self, by, value, attribute_name, timeout=None):
- """获取元素属性"""
- element = self.find_element(by, value, timeout)
- return element.get_attribute(attribute_name)
- def is_displayed(self, by, value, timeout=None):
- """检查元素是否显示"""
- try:
- element = self.find_visible_element(by, value, timeout)
- return element.is_displayed()
- except (NoSuchElementException, ElementNotVisibleException):
- return False
- def is_enabled(self, by, value, timeout=None):
- """检查元素是否启用"""
- try:
- element = self.find_element(by, value, timeout)
- return element.is_enabled()
- except NoSuchElementException:
- return False
- def is_selected(self, by, value, timeout=None):
- """检查元素是否被选中"""
- try:
- element = self.find_element(by, value, timeout)
- return element.is_selected()
- except NoSuchElementException:
- return False
- def select_dropdown_by_value(self, by, value, option_value, timeout=None):
- """通过值选择下拉选项"""
- from selenium.webdriver.support.ui import Select
- element = self.find_element(by, value, timeout)
- select = Select(element)
- select.select_by_value(option_value)
- def select_dropdown_by_text(self, by, value, option_text, timeout=None):
- """通过文本选择下拉选项"""
- from selenium.webdriver.support.ui import Select
- element = self.find_element(by, value, timeout)
- select = Select(element)
- select.select_by_visible_text(option_text)
- def select_dropdown_by_index(self, by, value, index, timeout=None):
- """通过索引选择下拉选项"""
- from selenium.webdriver.support.ui import Select
- element = self.find_element(by, value, timeout)
- select = Select(element)
- select.select_by_index(index)
- def get_dropdown_options(self, by, value, timeout=None):
- """获取下拉选项"""
- from selenium.webdriver.support.ui import Select
- element = self.find_element(by, value, timeout)
- select = Select(element)
- return [option.text for option in select.options]
- def hover(self, by, value, timeout=None):
- """鼠标悬停"""
- element = self.find_element(by, value, timeout)
- ActionChains(self.driver).move_to_element(element).perform()
- def double_click(self, by, value, timeout=None):
- """双击元素"""
- element = self.find_element(by, value, timeout)
- ActionChains(self.driver).double_click(element).perform()
- def right_click(self, by, value, timeout=None):
- """右键点击元素"""
- element = self.find_element(by, value, timeout)
- ActionChains(self.driver).context_click(element).perform()
- def drag_and_drop(self, source_by, source_value, target_by, target_value, timeout=None):
- """拖放元素"""
- source_element = self.find_element(source_by, source_value, timeout)
- target_element = self.find_element(target_by, target_value, timeout)
- ActionChains(self.driver).drag_and_drop(source_element, target_element).perform()
- def press_key(self, by, value, key, timeout=None):
- """按下键盘按键"""
- element = self.find_element(by, value, timeout)
- element.send_keys(key)
- def press_enter(self, by, value, timeout=None):
- """按下回车键"""
- self.press_key(by, value, Keys.ENTER, timeout)
- def press_tab(self, by, value, timeout=None):
- """按下Tab键"""
- self.press_key(by, value, Keys.TAB, timeout)
- def press_escape(self, by, value, timeout=None):
- """按下Esc键"""
- self.press_key(by, value, Keys.ESCAPE, timeout)
- # ==================== 等待方法 ====================
- def wait_for_element_present(self, by, value, timeout=None):
- """等待元素出现"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.presence_of_element_located((by, value)))
- def wait_for_element_visible(self, by, value, timeout=None):
- """等待元素可见"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.visibility_of_element_located((by, value)))
- def wait_for_element_invisible(self, by, value, timeout=None):
- """等待元素不可见"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.invisibility_of_element_located((by, value)))
- def wait_for_element_clickable(self, by, value, timeout=None):
- """等待元素可点击"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.element_to_be_clickable((by, value)))
- def wait_for_text_present(self, by, value, text, timeout=None):
- """等待元素包含特定文本"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.text_to_be_present_in_element((by, value), text))
- def wait_for_title_contains(self, text, timeout=None):
- """等待标题包含特定文本"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.title_contains(text))
- def wait_for_title_is(self, text, timeout=None):
- """等待标题等于特定文本"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.title_is(text))
- def wait_for_alert_present(self, timeout=None):
- """等待警告框出现"""
- wait = self.wait if timeout is None else WebDriverWait(self.driver, timeout)
- return wait.until(EC.alert_is_present())
- # ==================== 弹窗处理 ====================
- def accept_alert(self, timeout=None):
- """接受警告框"""
- alert = self.wait_for_alert_present(timeout)
- alert.accept()
- def dismiss_alert(self, timeout=None):
- """取消警告框"""
- alert = self.wait_for_alert_present(timeout)
- alert.dismiss()
- def get_alert_text(self, timeout=None):
- """获取警告框文本"""
- alert = self.wait_for_alert_present(timeout)
- return alert.text
- def input_alert_text(self, text, timeout=None):
- """向警告框输入文本"""
- alert = self.wait_for_alert_present(timeout)
- alert.send_keys(text)
- alert.accept()
- # ==================== Cookie操作 ====================
- def get_all_cookies(self):
- """获取所有Cookie"""
- return self.driver.get_cookies()
- def get_cookie_by_name(self, name):
- """根据名称获取Cookie"""
- return self.driver.get_cookie(name)
- def add_cookie(self, cookie_dict):
- """添加Cookie"""
- self.driver.add_cookie(cookie_dict)
- def delete_cookie(self, name):
- """删除指定Cookie"""
- self.driver.delete_cookie(name)
- def delete_all_cookies(self):
- """删除所有Cookie"""
- self.driver.delete_all_cookies()
- # ==================== JS执行 ====================
- def js_click(self, by, value, timeout=None):
- """通过JS点击元素"""
- element = self.find_element(by, value, timeout)
- self.execute_script("arguments[0].click();", element)
- def js_input_text(self, by, value, text, timeout=None):
- """通过JS输入文本"""
- element = self.find_element(by, value, timeout)
- self.execute_script("arguments[0].value = arguments[1];", element, text)
- def js_set_attribute(self, by, value, attr_name, attr_value, timeout=None):
- """通过JS设置元素属性"""
- element = self.find_element(by, value, timeout)
- self.execute_script(f"arguments[0].setAttribute('{attr_name}', '{attr_value}');", element)
- def js_remove_attribute(self, by, value, attr_name, timeout=None):
- """通过JS移除元素属性"""
- element = self.find_element(by, value, timeout)
- self.execute_script(f"arguments[0].removeAttribute('{attr_name}');", element)
- def js_scroll_to_element(self, by, value, timeout=None):
- """通过JS滚动到元素"""
- element = self.find_element(by, value, timeout)
- self.execute_script("arguments[0].scrollIntoView(true);", element)
- # ==================== 其他实用方法 ====================
- def switch_to_active_element(self):
- """切换到当前活动元素"""
- return self.driver.switch_to.active_element
- def get_page_source(self):
- """获取页面源码"""
- return self.driver.page_source
- def wait_for_page_load(self, timeout=30):
- """等待页面完全加载"""
- old_page = self.driver.find_element(By.TAG_NAME, 'html')
- yield
- WebDriverWait(self.driver, timeout).until(
- EC.staleness_of(old_page)
- )
- def is_alert_present(self, timeout=5):
- """检查警告框是否存在"""
- try:
- WebDriverWait(self.driver, timeout).until(EC.alert_is_present())
- return True
- except TimeoutException:
- return False
- def wait_for_ajax_complete(self, timeout=30):
- """等待AJAX请求完成"""
- js_condition = "return jQuery.active == 0"
- WebDriverWait(self.driver, timeout).until(
- lambda driver: self.execute_script(js_condition)
- )
- def highlight_element(self, by, value, timeout=None, duration=3):
- """高亮显示元素(用于调试)"""
- element = self.find_element(by, value, timeout)
- original_style = element.get_attribute("style")
- self.execute_script("arguments[0].setAttribute('style', arguments[1]);",
- element, "border: 2px solid red; border-style: dashed;")
- time.sleep(duration)
- self.execute_script("arguments[0].setAttribute('style', arguments[1]);",
- element, original_style)
|