圆弧派博客 - 专注于网络技术 https://www.iarc.top/ 圆弧派博客,是一个专注于网络技术分享的个人博客,包括但不止记录与分享编程知识、实用工具、开源项目,愿与更多志同道合的朋友共享网络乐趣! Selenium常用代码速查手册 https://www.iarc.top/515.html 2025-11-27T10:42:00+08:00 Selenium常用代码速查手册1. 基础配置用法:导入必要的模块,初始化浏览器驱动from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import ActionChains, Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from time import sleep # 初始化Chrome浏览器(需要先下载chromedriver) driver = webdriver.Chrome() driver.maximize_window() # 最大化窗口 driver.implicitly_wait(10) # 设置隐式等待10秒 # 打开网页 driver.get("https://www.baidu.com")2. 元素定位用法:在网页中找到你要操作的元素(按钮、输入框等)# CSS选择器(推荐使用,最灵活) element = driver.find_element(By.CSS_SELECTOR, "#id") # 通过id找元素 element = driver.find_element(By.CSS_SELECTOR, ".class") # 通过class找元素 element = driver.find_element(By.CSS_SELECTOR, "input[type='text']") # 通过属性找元素 # 其他定位方式 element = driver.find_element(By.ID, "element_id") # 直接通过id找 element = driver.find_element(By.CLASS_NAME, "class_name") # 通过class名找 element = driver.find_element(By.XPATH, "//div[@class='example']") # 通过xpath找 element = driver.find_element(By.TAG_NAME, "button") # 通过标签名找 element = driver.find_element(By.LINK_TEXT, "链接文本") # 通过链接文字找 element = driver.find_element(By.PARTIAL_LINK_TEXT, "部分链接") # 通过部分链接文字找 # 查找多个相同元素(返回列表) elements = driver.find_elements(By.CSS_SELECTOR, ".item")3. 基本操作用法:对找到的元素进行各种操作# 点击元素(按钮、链接等) element.click() # 在输入框中输入文本 element.send_keys("要输入的文本") # 清空输入框内容 element.clear() # 获取元素显示的文本内容 text = element.text print(text) # 打印获取的文本 # 获取元素的属性值(如value、href等) value = element.get_attribute("value") # 获取输入框的值 href = element.get_attribute("href") # 获取链接地址 # 判断元素状态 is_displayed = element.is_displayed() # 元素是否可见 is_enabled = element.is_enabled() # 元素是否可用 is_selected = element.is_selected() # 元素是否被选中(复选框、单选框)4. 键盘操作用法:模拟键盘按键,实现快捷键操作# 组合键操作(常用于复制粘贴等) element.send_keys(Keys.CONTROL, 'a') # Ctrl+A 全选文本 element.send_keys(Keys.CONTROL, 'c') # Ctrl+C 复制 element.send_keys(Keys.CONTROL, 'v') # Ctrl+V 粘贴 # 特殊按键 element.send_keys(Keys.ENTER) # 按回车键(提交表单) element.send_keys(Keys.TAB) # 按Tab键(切换焦点) element.send_keys(Keys.ESCAPE) # 按ESC键(取消操作) element.send_keys(Keys.DELETE) # 按Delete键 element.send_keys(Keys.BACKSPACE) # 按退格键 element.send_keys(Keys.ARROW_UP) # 按方向键上 # 实用示例:清空输入框并输入新内容 input_box = driver.find_element(By.ID, "search") input_box.send_keys(Keys.CONTROL, 'a') # 全选 input_box.send_keys(Keys.DELETE) # 删除 input_box.send_keys("新的搜索内容") # 输入新内容5. 鼠标操作用法:模拟鼠标的各种操作# 鼠标悬停(显示下拉菜单等) ActionChains(driver).move_to_element(element).perform() # 右键点击(显示右键菜单) ActionChains(driver).context_click(element).perform() # 双击元素 ActionChains(driver).double_click(element).perform() # 拖拽元素从source到target位置 ActionChains(driver).drag_and_drop(source, target).perform() # 拖拽元素到指定距离(x轴100像素,y轴0像素) ActionChains(driver).click_and_hold(element).move_by_offset(100, 0).release().perform() # 实用示例:滑动滑块 slider = driver.find_element(By.CSS_SELECTOR, ".slider") ActionChains(driver).click_and_hold(slider).move_by_offset(50, 0).release().perform()6. 等待机制用法:等待页面元素加载完成,避免操作失败# 固定等待(简单但不推荐,会浪费时间) sleep(2) # 等待2秒 # 显式等待(推荐使用,更智能) wait = WebDriverWait(driver, 10) # 最多等待10秒 # 等待元素出现在DOM中 element = wait.until(EC.presence_of_element_located((By.ID, "myElement"))) # 等待元素可以被点击 element = wait.until(EC.element_to_be_clickable((By.ID, "myButton"))) # 等待元素可见 element = wait.until(EC.visibility_of_element_located((By.ID, "myDiv"))) # 等待元素消失(如加载动画) wait.until(EC.invisibility_of_element_located((By.ID, "loading"))) # 实用示例:等待搜索结果加载 search_button = driver.find_element(By.ID, "search-btn") search_button.click() # 等待结果列表出现 results = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "results")))7. 下拉框操作用法:操作HTML的select下拉框from selenium.webdriver.support.ui import Select # 找到下拉框并创建Select对象 dropdown = driver.find_element(By.ID, "country") select = Select(dropdown) # 三种选择方式 select.select_by_visible_text("中国") # 通过显示文本选择 select.select_by_value("china") # 通过value属性选择 select.select_by_index(1) # 通过索引选择(从0开始) # 获取选项信息 all_options = select.options # 获取所有选项 selected_option = select.first_selected_option # 获取当前选中项 print(selected_option.text) # 打印选中项文本 # 取消选择(多选下拉框) select.deselect_by_visible_text("中国") select.deselect_all() # 取消所有选择8. 窗口和标签页用法:处理多个浏览器窗口或标签页# 保存当前窗口句柄(用于后续切换回来) main_window = driver.current_window_handle # 获取所有窗口句柄 all_windows = driver.window_handles print(f"共有{len(all_windows)}个窗口") # 点击链接打开新窗口后,切换到新窗口 link = driver.find_element(By.LINK_TEXT, "打开新窗口") link.click() # 切换到最新打开的窗口 driver.switch_to.window(driver.window_handles[-1]) # 用JavaScript打开新标签页 driver.execute_script("window.open('https://www.baidu.com');") # 关闭当前窗口并切换回主窗口 driver.close() driver.switch_to.window(main_window) # 处理iframe框架 driver.switch_to.frame("frame_name") # 切换到iframe driver.switch_to.frame(0) # 通过索引切换 driver.switch_to.default_content() # 切回主页面 # 实用示例:处理弹出窗口 original_window = driver.current_window_handle # 点击按钮打开新窗口 driver.find_element(By.ID, "open-window").click() # 等待新窗口出现 wait.until(lambda d: len(d.window_handles) > 1) # 切换到新窗口 for window in driver.window_handles: if window != original_window: driver.switch_to.window(window) break9. JavaScript执行用法:执行JavaScript代码解决复杂操作# 滚动页面到底部(加载更多内容) driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") # 滚动到指定元素位置 element = driver.find_element(By.ID, "target") driver.execute_script("arguments[0].scrollIntoView();", element) # 强制点击被遮挡的元素 hidden_button = driver.find_element(By.ID, "hidden-btn") driver.execute_script("arguments[0].click();", hidden_button) # 直接设置输入框的值(绕过输入限制) input_box = driver.find_element(By.ID, "readonly-input") driver.execute_script("arguments[0].value = '强制设置的值';", input_box) # 修改元素样式(如显示隐藏元素) driver.execute_script("arguments[0].style.display = 'block';", element) # 获取页面信息 page_height = driver.execute_script("return document.body.scrollHeight;") print(f"页面高度:{page_height}像素") # 实用示例:无限滚动加载 last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") sleep(2) # 等待加载 new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break # 没有新内容了 last_height = new_height10. 文件操作用法:处理文件上传和截图# 文件上传(找到文件选择器并传入文件路径) file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']") file_path = r"C:\Users\用户名\Desktop\要上传的文件.jpg" file_input.send_keys(file_path) # 多文件上传 files = [r"C:\file1.jpg", r"C:\file2.jpg"] file_input.send_keys("\n".join(files)) # 整个页面截图 driver.save_screenshot("页面截图.png") # 单个元素截图 element = driver.find_element(By.ID, "target") element.screenshot("元素截图.png") # 带时间戳的截图(避免文件名重复) from datetime import datetime timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") driver.save_screenshot(f"截图_{timestamp}.png") # 实用示例:自动化测试截图 def take_screenshot_on_error(): try: # 执行测试步骤 driver.find_element(By.ID, "submit").click() except Exception as e: # 出错时自动截图 driver.save_screenshot("错误截图.png") print(f"操作失败:{e}")11. 弹窗处理用法:处理JavaScript弹出的对话框# 等待弹窗出现并处理 try: # 触发弹窗的操作 driver.find_element(By.ID, "alert-btn").click() # 切换到弹窗 alert = driver.switch_to.alert # 获取弹窗文本 alert_text = alert.text print(f"弹窗内容:{alert_text}") # 确认弹窗(点击确定) alert.accept() # 或者取消弹窗(点击取消) # alert.dismiss() except: print("没有弹窗出现") # 处理输入型弹窗(prompt) try: driver.find_element(By.ID, "prompt-btn").click() alert = driver.switch_to.alert alert.send_keys("要输入的文本") # 在弹窗中输入文本 alert.accept() # 确认 except: print("没有输入弹窗") # 实用示例:批量确认删除操作 delete_buttons = driver.find_elements(By.CLASS_NAME, "delete-btn") for btn in delete_buttons: btn.click() # 等待确认弹窗 alert = WebDriverWait(driver, 5).until(lambda d: d.switch_to.alert) alert.accept() # 确认删除12. Cookie操作用法:管理浏览器Cookie,实现登录状态保持等# 添加Cookie(通常用于模拟登录状态) driver.add_cookie({ "name": "session_id", "value": "abc123456", "domain": "example.com" }) # 获取指定Cookie session_cookie = driver.get_cookie("session_id") if session_cookie: print(f"会话ID:{session_cookie['value']}") # 获取所有Cookie all_cookies = driver.get_cookies() for cookie in all_cookies: print(f"{cookie['name']}: {cookie['value']}") # 删除指定Cookie driver.delete_cookie("session_id") # 删除所有Cookie(退出登录) driver.delete_all_cookies() # 实用示例:保存和恢复登录状态 import json # 登录后保存Cookie def save_cookies(): with open("cookies.json", "w") as f: json.dump(driver.get_cookies(), f) # 下次访问时恢复Cookie def load_cookies(): try: with open("cookies.json", "r") as f: cookies = json.load(f) for cookie in cookies: driver.add_cookie(cookie) driver.refresh() # 刷新页面使Cookie生效 except FileNotFoundError: print("没有保存的Cookie文件")13. 浏览器控制用法:控制浏览器的基本行为# 页面导航 driver.get("https://www.baidu.com") # 打开网页 driver.back() # 后退到上一页 driver.forward() # 前进到下一页 driver.refresh() # 刷新当前页面 # 窗口大小控制 driver.maximize_window() # 最大化窗口 driver.minimize_window() # 最小化窗口 driver.set_window_size(1920, 1080) # 设置窗口大小 driver.fullscreen_window() # 全屏模式 # 获取窗口大小和位置 size = driver.get_window_size() print(f"窗口大小:{size['width']} x {size['height']}") position = driver.get_window_position() print(f"窗口位置:({position['x']}, {position['y']})") # 获取页面信息 title = driver.title # 获取页面标题 url = driver.current_url # 获取当前URL page_source = driver.page_source # 获取页面源码 print(f"页面标题:{title}") print(f"当前网址:{url}") # 实用示例:检查页面是否正确加载 def check_page_loaded(expected_title): actual_title = driver.title if expected_title in actual_title: print("页面加载成功") return True else: print(f"页面加载异常,期望标题包含:{expected_title},实际标题:{actual_title}") return False # 设置浏览器位置(多显示器环境) driver.set_window_position(0, 0) # 移动到左上角14. 常用操作模式用法:封装常用的操作组合,提高代码复用性# 清空输入框并输入新内容(最常用) def input_text(element, text): element.click() # 点击激活输入框 element.send_keys(Keys.CONTROL, 'a') # 全选现有内容 element.send_keys(Keys.DELETE) # 删除内容 element.send_keys(text) # 输入新内容 # 使用示例 search_box = driver.find_element(By.ID, "search") input_text(search_box, "Python教程") # 等待并点击(避免元素未加载完成) def wait_and_click(driver, selector, timeout=10): element = WebDriverWait(driver, timeout).until( EC.element_to_be_clickable((By.CSS_SELECTOR, selector)) ) element.click() return element # 使用示例 wait_and_click(driver, "#submit-btn") # 滚动到元素并点击(处理页面很长的情况) def scroll_and_click(driver, element): driver.execute_script("arguments[0].scrollIntoView();", element) sleep(0.5) # 等待滚动完成 element.click() # 安全点击(多种点击方式的组合) def safe_click(driver, element): try: element.click() # 尝试普通点击 except ElementClickInterceptedException: # 如果被遮挡,用JS点击 driver.execute_script("arguments[0].click();", element) # 批量操作示例 def batch_delete_items(): items = driver.find_elements(By.CLASS_NAME, "item") for item in items: delete_btn = item.find_element(By.CLASS_NAME, "delete") safe_click(driver, delete_btn) sleep(1) # 等待删除完成15. 异常处理用法:处理自动化过程中的各种异常情况from selenium.common.exceptions import * # 基本异常处理 try: element = driver.find_element(By.ID, "submit") element.click() except NoSuchElementException: print("找不到提交按钮,可能页面结构发生变化") except TimeoutException: print("页面加载超时,网络可能有问题") except ElementClickInterceptedException: print("按钮被其他元素遮挡,尝试滚动页面") except StaleElementReferenceException: print("元素引用已失效,需要重新查找元素") # 完整的异常处理示例 def robust_click(driver, selector, max_retries=3): """健壮的点击函数,包含重试机制""" for attempt in range(max_retries): try: element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, selector)) ) element.click() return True # 成功点击 except TimeoutException: print(f"第{attempt+1}次尝试:等待元素超时") except ElementClickInterceptedException: print(f"第{attempt+1}次尝试:元素被遮挡,尝试滚动") driver.execute_script("window.scrollBy(0, 200);") except Exception as e: print(f"第{attempt+1}次尝试:未知错误 {e}") if attempt < max_retries - 1: sleep(2) # 重试前等待 print("所有尝试都失败了") return False # 使用示例 if robust_click(driver, "#difficult-button"): print("成功点击按钮") else: print("点击失败,需要人工检查")16. 性能优化用法:提高自动化脚本的运行速度和稳定性# Chrome浏览器性能优化配置 chrome_options = webdriver.ChromeOptions() # 禁用图片加载(大幅提升速度) chrome_options.add_argument('--blink-settings=imagesEnabled=false') # 无头模式(不显示浏览器界面,速度更快) chrome_options.add_argument('--headless') # 禁用GPU加速(避免某些环境下的问题) chrome_options.add_argument('--disable-gpu') # 禁用开发者工具 chrome_options.add_argument('--disable-dev-shm-usage') # 设置页面加载策略(不等待所有资源加载完成) chrome_options.add_argument('--page-load-strategy=eager') # 禁用扩展 chrome_options.add_argument('--disable-extensions') # 禁用通知 chrome_options.add_argument('--disable-notifications') # 创建优化后的驱动 driver = webdriver.Chrome(options=chrome_options) # 设置较短的页面加载超时 driver.set_page_load_timeout(30) # 30秒超时 # 实用示例:批量处理时的优化 def optimized_batch_process(): # 使用无头模式进行批量处理 options = webdriver.ChromeOptions() options.add_argument('--headless') options.add_argument('--disable-images') driver = webdriver.Chrome(options=options) urls = ["http://example1.com", "http://example2.com"] results = [] for url in urls: driver.get(url) # 快速获取需要的信息 title = driver.title results.append(title) driver.quit() return results17. 调试技巧用法:帮助定位和解决自动化脚本中的问题# 高亮显示元素(方便调试时查看) def highlight_element(driver, element, color="red", width=3): """高亮显示元素""" original_style = element.get_attribute("style") driver.execute_script( f"arguments[0].style.border='{width}px solid {color}';", element ) sleep(2) # 显示2秒 # 恢复原始样式 driver.execute_script(f"arguments[0].style='{original_style}';", element) # 获取元素详细信息 def get_element_info(element): """获取元素的详细信息用于调试""" info = { "tag_name": element.tag_name, "text": element.text, "location": element.location, "size": element.size, "is_displayed": element.is_displayed(), "is_enabled": element.is_enabled() } return info # 使用示例 button = driver.find_element(By.ID, "submit") print("按钮信息:", get_element_info(button)) highlight_element(driver, button) # 高亮显示按钮 # 检查元素是否在视口内 def is_element_in_viewport(driver, element): """检查元素是否在当前视口内""" return driver.execute_script(""" var rect = arguments[0].getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth ); """, element) # 调试模式运行(添加详细日志) def debug_click(driver, selector): """调试版本的点击函数""" print(f"正在查找元素:{selector}") try: element = driver.find_element(By.CSS_SELECTOR, selector) print(f"找到元素:{element.tag_name}") if not element.is_displayed(): print("警告:元素不可见") if not element.is_enabled(): print("警告:元素不可用") if not is_element_in_viewport(driver, element): print("元素不在视口内,滚动到元素位置") driver.execute_script("arguments[0].scrollIntoView();", element) highlight_element(driver, element) # 高亮显示 element.click() print("成功点击元素") except Exception as e: print(f"点击失败:{e}") driver.save_screenshot("debug_error.png") # 出错时截图18. 移动端测试用法:模拟移动设备进行测试# 模拟不同移动设备 mobile_devices = { "iPhone X": {"deviceName": "iPhone X"}, "iPad": {"deviceName": "iPad"}, "Galaxy S5": {"deviceName": "Galaxy S5"}, "自定义": { "deviceMetrics": { "width": 375, "height": 667, "pixelRatio": 2.0 }, "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_0 like Mac OS X)" } } # 创建移动端浏览器 def create_mobile_driver(device="iPhone X"): chrome_options = webdriver.ChromeOptions() chrome_options.add_experimental_option( "mobileEmulation", mobile_devices[device] ) return webdriver.Chrome(options=chrome_options) # 使用示例 mobile_driver = create_mobile_driver("iPhone X") mobile_driver.get("https://m.baidu.com") # 触摸操作(注意:TouchActions在新版本中已弃用) # 推荐使用ActionChains进行移动端操作 def mobile_swipe(driver, start_x, start_y, end_x, end_y): """模拟手机滑动操作""" ActionChains(driver)\ .move_by_offset(start_x, start_y)\ .click_and_hold()\ .move_by_offset(end_x - start_x, end_y - start_y)\ .release()\ .perform() # 移动端特有操作示例 def mobile_test_example(): driver = create_mobile_driver("iPhone X") driver.get("https://m.taobao.com") # 模拟向下滑动加载更多 for i in range(3): driver.execute_script("window.scrollBy(0, 500);") sleep(2) # 检查移动端特有元素 try: menu_btn = driver.find_element(By.CLASS_NAME, "mobile-menu") menu_btn.click() print("成功打开移动端菜单") except: print("未找到移动端菜单") driver.quit() # 响应式测试(测试不同屏幕尺寸) def responsive_test(): driver = webdriver.Chrome() # 测试不同分辨率 resolutions = [ (1920, 1080), # 桌面 (1366, 768), # 笔记本 (768, 1024), # 平板 (375, 667) # 手机 ] for width, height in resolutions: driver.set_window_size(width, height) driver.get("https://example.com") # 检查布局是否正常 title = driver.title print(f"分辨率 {width}x{height}: {title}") # 截图保存 driver.save_screenshot(f"responsive_{width}x{height}.png") sleep(2) driver.quit()19. 参数化测试用法:使用不同的测试数据多次运行同一个测试,提高测试覆盖率import pytest # 基本参数化测试 @pytest.mark.parametrize("username,password", [ ("user1", "pass1"), ("user2", "pass2"), ("admin", "admin123") ]) def test_login(driver, username, password): """测试不同用户的登录功能""" driver.get("https://example.com/login") # 输入用户名 username_input = driver.find_element(By.ID, "username") username_input.send_keys(username) # 输入密码 password_input = driver.find_element(By.ID, "password") password_input.send_keys(password) # 点击登录 login_btn = driver.find_element(By.ID, "login-btn") login_btn.click() # 验证登录结果 assert "欢迎" in driver.page_source # 多参数参数化测试 @pytest.mark.parametrize("start_city,end_city,date,expected_result", [ ("北京", "上海", "2024-12-01", "航班信息"), ("广州", "深圳", "2024-12-02", "航班信息"), ("成都", "重庆", "2024-12-03", "航班信息") ]) def test_flight_search(driver, start_city, end_city, date, expected_result): """测试航班搜索功能""" driver.get("https://flights.example.com") # 输入出发城市 start_input = driver.find_element(By.ID, "departure") start_input.clear() start_input.send_keys(start_city) # 输入到达城市 end_input = driver.find_element(By.ID, "arrival") end_input.clear() end_input.send_keys(end_city) # 选择日期 date_input = driver.find_element(By.ID, "date") date_input.clear() date_input.send_keys(date) # 搜索 search_btn = driver.find_element(By.ID, "search") search_btn.click() # 等待结果 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, "flight-results")) ) # 验证结果 assert expected_result in driver.page_source # 使用字典进行参数化(更清晰的数据结构) test_data = [ { "name": "测试用例1", "url": "https://example1.com", "title": "Example 1", "screenshot": "test1.png" }, { "name": "测试用例2", "url": "https://example2.com", "title": "Example 2", "screenshot": "test2.png" } ] @pytest.mark.parametrize("test_case", test_data) def test_website_title(driver, test_case): """测试网站标题""" driver.get(test_case["url"]) # 等待页面加载 WebDriverWait(driver, 10).until( EC.title_contains(test_case["title"]) ) # 截图 driver.save_screenshot(test_case["screenshot"]) # 验证标题 assert test_case["title"] in driver.title # 从外部文件读取测试数据 import json def load_test_data(file_path): """从JSON文件加载测试数据""" with open(file_path, 'r', encoding='utf-8') as f: return json.load(f) # 创建测试数据文件 test_data.json """ [ {"city": "北京", "keyword": "美食", "expected": "餐厅"}, {"city": "上海", "keyword": "景点", "expected": "旅游"}, {"city": "广州", "keyword": "购物", "expected": "商场"} ] """ @pytest.mark.parametrize("data", load_test_data("test_data.json")) def test_search_with_external_data(driver, data): """使用外部数据进行搜索测试""" driver.get("https://map.baidu.com") # 搜索 search_box = driver.find_element(By.ID, "sole-input") search_box.clear() search_box.send_keys(f"{data['city']} {data['keyword']}") search_btn = driver.find_element(By.ID, "search-button") search_btn.click() # 等待结果 sleep(3) # 验证结果包含期望内容 assert data['expected'] in driver.page_source # 条件参数化(根据条件跳过某些测试) @pytest.mark.parametrize("browser,url", [ ("chrome", "https://example.com"), ("firefox", "https://example.com"), pytest.param("safari", "https://example.com", marks=pytest.mark.skipif(True, reason="Safari not available")) ]) def test_cross_browser(browser, url): """跨浏览器测试""" if browser == "chrome": driver = webdriver.Chrome() elif browser == "firefox": driver = webdriver.Firefox() driver.get(url) assert "Example" in driver.title driver.quit() # 参数化测试类 class TestUserManagement: @pytest.mark.parametrize("user_type,expected_menu", [ ("admin", "用户管理"), ("user", "个人中心"), ("guest", "登录") ]) def test_user_menu(self, driver, user_type, expected_menu): """测试不同用户类型的菜单""" # 模拟不同用户登录 self.login_as_user(driver, user_type) # 检查菜单 menu = driver.find_element(By.CLASS_NAME, "user-menu") assert expected_menu in menu.text def login_as_user(self, driver, user_type): """辅助方法:模拟不同类型用户登录""" users = { "admin": ("admin", "admin123"), "user": ("testuser", "test123"), "guest": (None, None) } if users[user_type][0]: # 如果不是guest driver.get("https://example.com/login") username, password = users[user_type] driver.find_element(By.ID, "username").send_keys(username) driver.find_element(By.ID, "password").send_keys(password) driver.find_element(By.ID, "login-btn").click() else: driver.get("https://example.com") # guest直接访问首页 # 实用示例:电商网站商品搜索测试 @pytest.mark.parametrize("keyword,min_results,screenshot_name", [ ("手机", 10, "phone_search.png"), ("笔记本电脑", 5, "laptop_search.png"), ("耳机", 8, "headphone_search.png"), ("", 0, "empty_search.png") # 测试空搜索 ]) def test_product_search(driver, keyword, min_results, screenshot_name): """测试商品搜索功能""" driver.get("https://shop.example.com") # 搜索商品 search_box = driver.find_element(By.ID, "search-input") search_box.clear() if keyword: # 如果关键词不为空 search_box.send_keys(keyword) search_btn = driver.find_element(By.ID, "search-btn") search_btn.click() # 等待搜索结果 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, "product-list")) ) # 截图 driver.save_screenshot(screenshot_name) # 验证结果数量 products = driver.find_elements(By.CLASS_NAME, "product-item") if keyword: # 有关键词时应该有结果 assert len(products) >= min_results, f"搜索'{keyword}'的结果少于{min_results}个" else: # 空搜索可能没有结果或显示默认商品 print(f"空搜索返回{len(products)}个结果") 五分钟开发ToDoListAPP后端 https://www.iarc.top/499.html 2025-08-14T21:15:00+08:00 使用CodeBuddy IDE五分钟内即可完成ToDoList基础后端开发,在这个AI工具发达的时代,我们已不需要将全部的知识装进大脑,只需有一个大的框架,细节交给AI即可快速建立项目。环境配置:Node.js将项目需求描述给codebuddy,我这里模型选的是GPT-5-nano,只需稍等几十秒钟,项目将会完全构建以下是codebuddy生成的项目(未进行任何修改)index.js:const express = require('express'); const app = express(); const port = process.env.PORT || 3000; // In-memory storage let todos = []; let nextId = 1; function findTodo(id) { return todos.find(t => t.id === id); } app.use(express.json()); // Get all todos, with optional filtering by completion status app.get('/todos', (req, res) => { const completed = req.query.completed; if (completed !== undefined) { const isDone = completed === 'true'; return res.json(todos.filter(t => t.completed === isDone)); } res.json(todos); }); // Get a single todo by id app.get('/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); const t = todos.find(t => t.id === id); if (!t) return res.status(404).json({ error: 'Todo not found' }); res.json(t); }); // Create a new todo app.post('/todos', (req, res) => { const { title, description } = req.body; if (!title) return res.status(400).json({ error: 'title is required' }); const todo = { id: nextId++, title, description: description || '', completed: false, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; todos.push(todo); res.status(201).json(todo); }); // Update an existing todo app.put('/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); const t = todos.find(t => t.id === id); if (!t) return res.status(404).json({ error: 'Todo not found' }); const { title, description, completed } = req.body; if (title !== undefined) t.title = title; if (description !== undefined) t.description = description; if (completed !== undefined) t.completed = completed; t.updatedAt = new Date().toISOString(); res.json(t); }); // Delete a todo app.delete('/todos/:id', (req, res) => { const id = parseInt(req.params.id, 10); const idx = todos.findIndex(t => t.id === id); if (idx === -1) return res.status(404).json({ error: 'Todo not found' }); const removed = todos.splice(idx, 1); res.json(removed[0]); }); // Health check (optional) app.get('/health', (req, res) => { res.json({ status: 'ok', todoCount: todos.length }); }); app.listen(port, () => { console.log(`Todo backend listening at http://localhost:${port}`); }); package.json{ "name": "todolist-backend", "version": "1.0.0", "description": "In-memory Todo List backend using Node.js + Express", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.18.2" } }接下来进行npm安装项目运行所需的库,安装完后直接开始运行看看能不能正常跑起来测试阶段:测试接口:(内存存储,重启丢失数据)请求方式路径功能GET/todos获取所有待办,可通过查询参数 completed=true/false 进行筛选POST/todos创建待办,body 示例 { "title": "示例", "description": "可选" }GET/todos/:id获取指定待办PUT/todos/:id更新待办,支持 title、description、completedDELETE/todos/:id删除待办GET/health健康检查获取所有待办:目前初始化成功但还没有添加数据创建待办由于我没有进行前端的编写,这里直接在浏览器控制台模拟前端js发送请求完成接下来的测试,js代码如下:fetch("/todos", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "title": "待办名字", "description": "待办描述" }) })已成功创建两个待办事项,重新get请求todos可查看已成功添加通过id获取指定待办信息更新已有待办事项内容成功更新删除待办事项健康检测注意事项: 该版本的待办事项数据仅保存在内存,重启后将全部丢失,仅适合开发/测试阶段。不过接下来可以让codebuddy优化成使用json文件存储或者使用数据库(SQLite、PostgreSQL、MongoDB 等)存储数据,交给各位去继续探索了。评论区留言“CodeBuddy”抽5位送永久体验码!CodeBuddyIDE官网:https://www.codebuddy.ai/我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=6g36nynyzup Github账号只要满180天,即可终身享受免费4核8G服务器搭建Alist网盘 https://www.iarc.top/492.html 2025-08-01T22:39:00+08:00 ClawCloud Run,它是阿里云青春版Claw Cloud家的,有点像Vercel那种在线开发平台。不管是啥应用、程序,包括Docker应用,都能快速部署,现在已经支持76款热门开源应用一键搞定了。福利这块:如果你的GitHub账号注册满180天,能终身享受每月5美金的免费额度;新用户刚注册,也会直接送5美金体验额度,但用完就没了。资源配置呢,免费套餐最高能给到10GB流量、4核vCPU、8GB内存、10GB磁盘空间,还有1个工作区,很适合用来部署轻量级的小应用。举个例子,部署Alist搭个个人网盘管理系统,一天下来也就0.07刀,每月5刀的免费额度完全够用,轻量场景用着特别合适。注册也简单,直接用GitHub账号登录就行。可选地区有美国东部、德国、美国西部、新加坡和日本。从国内访问速度看,新加坡和日本这两个节点更推荐。注册完之后,界面上会显示几个核心功能模块:App Launchpad(应用启动)、Database(数据库)、Devbox(开发沙盒)、Object Storage(对象存储)、App Store(应用商店)和Terminal(终端)。注册地址在这:https://console.run.claw.cloud/signin?link=BSYQATGONVWT 祝各位2025新年快乐,这是一份新年礼物,免费主机二级域名等 https://www.iarc.top/482.html 2025-01-29T16:22:00+08:00 瑞蛇携福至,好运满征途。新的一年,祝您蛇来运转,巳巳如意,创新无限,前程似锦。新年快乐🎉🎉赠送100台康乐主机活动链接:http://idc.arcpi.cn免费二级域名212025.xyz公益二级域名:http://212025.xyz祝福网页在线生成制作地址:http://web.iarc.top 油管无水印下载视频工具 https://www.iarc.top/480.html 2025-01-27T13:33:00+08:00 工具展示最高可支持8K无水印视频下载使用需知该工具为英文,如果有的看不懂需要用翻译软件,然后下载速度取决于你的梯的速度,支持下载视频合集。下载地址{cloud title="油管无水印视频下载" type="default" url="https://pan.quark.cn/s/9f01f8c5ee7b" password=""/} 魔幻粒子新年快乐祝福源码 https://www.iarc.top/479.html 2025-01-27T13:23:00+08:00 效果图源码介绍魔幻粒子新年祝福是一段基于HTML5 Canvas制作的粒子爆炸,矩阵显字的动画特效代码,给人一种非常大气的视觉感,欢迎对此段代码感兴趣的朋友前来下载使用。源码由HTML+CSS+JS组成,记事本打开源码文件可以进行内容文字之类的修改下载地址{cloud title="魔幻粒子新年祝福源码" type="default" url="https://pan.quark.cn/s/3323cd0b8b51" password=""/} 大陆和香港高性价比云服务器推荐两家,都有着十几年沉淀的大厂 https://www.iarc.top/461.html 2024-07-24T01:14:00+08:00 本文所提及的服务器商都是本站所用过至少1年的,2核2G服务器每年的价格都是在100元以下(续费不涨价),比一些小厂的还实惠,个人感觉没必要按月去租,既用了就买个一年的更具性价比。阿里云1年配置99元2核2G,3M固定带宽不限流量,40G ESSD Entry云盘{abtn icon="fa-diamond" color="#ff6800" href="https://www.aliyun.com/benefit?scm=20140722.M_185600978.P_114.MO_2274-ID_10517682-MID_10517682-CID_31491-ST_11142-V_1&source=5176.29345612&userCode=m2urtzth" radius="5px" content="点我前往阿里云活动页"/} 性价比{progress percentage="90%" color="#fff56b"/}宽带只有3M,装个win10系统当成云电脑从网上下文件网速几十M比3M快多了,但是从服务器上下文件到本地就3M左右,个人博客类的站点够用。稳定性{progress percentage="99%" color="#fff56b"/}排除被人为打黑洞里了一次,用了一年期间没有连不上的情况。野草云1年配置99元2核2G,100Mbps优质BGP宽带每月限600GB流量(超出限速1M),30GB SSD存储香港AMD Linux VPS折后价格表:1年配置81.4元1核1G,100Mbps优质BGP,600GB月流量(超出限速1M),15GB SSD存储96.2元1核2G,100Mbps优质BGP,600GB月流量(超出限速1M),15GB SSD存储一年付3.8折优惠码:12THBIRTHDAY {abtn icon="fa-diamond" color="#ff6800" href="https://my.yecaoyun.com/aff.php?aff=2415" radius="5px" content="点我前往野草云活动页"/}性价比{progress percentage="100%" color="#fff56b"/}100MbpsBGP线路在国内实测下载速度是10M左右,比3M快了三四倍。就是一个月只有600GB流量,超过600GB就会被限速,我这一年用的过程中一个月最高用的还不到100GB了,正常建网站完全够用,如果用这搭梯子翻墙的话用的可能多一点。下载应用确实比国内服务器舒服,不用弄镜像源了,这可以直连github等代码仓库。稳定性{progress percentage="80%" color="#fff56b"/}一年里有两次断网超过12小时(都是小概率事件都被我撞上了),我看他们公告发了几次重启断网公告,这我倒是没察觉到。财务系统被入侵了,强制给我重置了root密码并关机了 ::(黑线) 香港地震给机房震断电了最后目前我就这两家的服务器用的时长都超过一年了(内陆阿里云,海外野草云),其他家的没用过不做评价。腾讯云、华为云、移动云等这些国内有名的也有很多便宜的服务器可以关注一下,但都是大陆空间都需要icp备案。野草云除了隔几个月用十几分钟重启一下,没有啥毛病了,网速能接受,用来装xui最合适了,也是运营了12年应该不会跑路的。不过要极致稳定就选阿里云,要宽带和基本稳定就选野草云,香港离大陆也不算远,延迟不算高,给网站套个国内的CDN也可以缓解延迟。如果有更便宜更具性价比的服务器欢迎留言:@(献花) Joe文章列表添加渐变颜色效果 https://www.iarc.top/452.html 2024-07-07T00:41:00+08:00 一个大气的文章列表CSS渐变动画,也可以使用图片作为渐变背景,,效果如下(鼠标移动到元素上后颜色会更加突出):日间模式夜间模式接下来需要编辑的文件以及相对Joe主题的文件路径:joe.index.js /Joe/assets/jsjoe.index.css /Joe/assets/cssjoe.mode.css/Joe/assets/css开始(共三部分){tabs}{tabs-pane label="添加HTML代码"}打开joe.index.js文件找到如图所示位置可以直接搜joe_list__item wow default定位到,其实一打开就是了。在第一个a标签元素后面加入如下代码<div class="article-banner-wrap"></div> <div class="article-banner"></div>{/tabs-pane}{tabs-pane label="添加CSS代码"}直接将下面的css代码复制粘贴到joe.index.css文件的最后面就行了/*首页列表渐变*/ .article-banner-wrap { position: absolute; height: 100%; width: 50%; right: 0; top: 0; } .article-banner { visibility: hidden; opacity: .2; position: absolute; height: 100%; width: 50%; right: 0; top: 0; z-index: 0; background-repeat: no-repeat; background-size: cover; -webkit-background-size: cover; -o-background-size: cover; background-position: center center; transition: opacity 0.2s; -webkit-mask-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 100%); border-radius: 8px; background:linear-gradient(to left,#2BC0E4,#EAECC6); visibility: visible; animation: banner-show 1s; } .joe_list__item.default:hover .article-banner{opacity: 1;}其中的background可以改成图片地址,这样效果就是图片了,但图片会拖累网站加载速度,可自行决定是否要换成图片。{/tabs-pane}{tabs-pane label="适配夜间模式"}打开joe.mode.css文件,将以下CSS代码加入文件底部即可。/*首页列表图片渐变夜间模式*/ html[data-night='night'] .article-banner{ background: linear-gradient(to left,#1F1C2C,#928DAB); opacity:0.1 }我这里不是最底部是因为我后来又加其他东西了,其实也不是一定要最底部,只是方便小白操作和自己描述了。{/tabs-pane}{/tabs} 一款自适应的开源纯静态音乐播放器 https://www.iarc.top/446.html 2024-05-05T16:40:00+08:00 一个基于Aplayer和MetingJS的静态音乐播放器预览{anote icon="music" href="https://lab.iarc.top/concert/" type="info" content="音乐厅"/} 基本操作Space空格键:暂停/播放音乐上/下方向键:增加/减少音量左/右方向键:上一曲/下一曲ID播放列表的id,可以从音乐歌单分享的链接中获取,例如https://y.qq.com/n/ryqq/playlist/8668419170中,id为8668419170网易云也同理。Server播放列表的服务商,例如netease(网易云音乐),tencent(腾讯),kugou(酷狗),xiami(小米音乐),baidu(百度音乐)使用URL参数(推荐)支持URL参数 https://lab.iarc.top/concert/?id=+ id +&server= + server例:鸡你太美: https://lab.iarc.top/concert/?id=2762963245&server=netease项目开源地址原作者开源地址:{cloud title="原版地址" type="github" url="https://github.com/zhheo/HeoMusic" password=""/}圆弧派二开地址:{cloud title="二开地址" type="github" url="https://github.com/QingDi2/lab/tree/main/concert" password=""/}二开新增功能:下载、标题、网易云歌单id输入框,其余原版功能未做删减。全开源各位可以随便改 用cfpages免费建个干净大气的程序介绍页[附源码] https://www.iarc.top/437.html 2024-05-04T22:35:00+08:00 引流方法之一,都知道微信小程序只能在微信内搜索到,在百度搜索引擎等搜不到,所以建个单页有助于从搜索引擎上获得用户。介绍页演示站:https://mxam.arcpi.cn演示图:源码都是静态文件,所以直接用cf pages网站托管平台免费建,当时vercel也可以的。cf pages官网地址:戳我前往(无需魔法也能正常用)选免费套餐就行,注册个号进去后也不用实名验证啥的,可以直接创建项目,然后把源码压缩包往里面一丢他会自动解压,最后cname解析一下域名就OK了源码下载:{hide}{cloud title="程序介绍页" type="lz" url="https://xql.lanzouw.com/icQsm1xp287c" password=""/}那个小程序源码好像都泛滥了,要是没泛滥的话留个言,过几天我再发出来吧{/hide}