自动化实现web端Google SignUp——selenium
案例:自动化获取Google注册页面——selenium
前言
提示:通过案例掌握selenium语法
涉及技术:Python + Selenium
在本文中,我们将通过一个实际案例来学习如何使用Selenium自动化工具模拟Google账号注册流程。这个案例涵盖了Selenium的多种高级用法,包括元素定位、表单填写、下拉框操作、异常处理等,非常适合想要深入学习Web自动化的读者。
一、目标即结果
1. 目标:
自动化完成Google账号注册流程,包括填写个人信息、选择用户名、设置密码、验证手机号等步骤。
2. 提前了解网页信息
- 注册入口:https://accounts.google.com/signup
- 注册流程包含多个步骤:
- 填写姓名
- 填写生日和性别
- 选择Gmail地址
- 设置密码
- 电话号码验证
- 添加恢复邮箱(可选)
- 同意隐私政策和条款
3. 结果
成功完成Google账号注册流程,获取新的Gmail账号。
图片就不放了,不能过审
二、逐步分析
1. Selenium环境配置
首先,我们需要正确配置Selenium环境,包括导入必要的库和设置WebDriver:
import time
from selenium import webdriver
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.support.ui import Select
from selenium.common.exceptions import TimeoutException, NoSuchElementException# WebDriver 配置
options = webdriver.ChromeOptions()
# 更新 User-Agent 为最新版本
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.115 Safari/537.36")# 禁用自动化标志
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)# 添加新的反自动化检测参数
options.add_argument("--disable-blink-features=AutomationControlled")# 添加其他有用的配置
options.add_argument("--disable-notifications") # 禁用通知
options.add_argument("--disable-popup-blocking") # 禁用弹窗拦截
options.add_argument("--disable-infobars") # 禁用信息栏
options.add_argument("--start-maximized") # 启动时最大化窗口# 设置 CDP 命令以修改 webdriver 相关参数
options.add_argument("--remote-debugging-port=9222") # 开启调试端口# 使用 Service 对象指定路径
service = webdriver.ChromeService()
driver = webdriver.Chrome(service=service, options=options)wait = WebDriverWait(driver, 11) # 设置显式等待,最多等待11秒
这段代码中,我们特别注意以下几点:
- 使用最新的User-Agent
- 禁用自动化标志,避免被网站检测
- 设置显式等待,提高脚本稳定性
2. 填写姓名
# 打开 Google 账号注册页面
signup_url = "https://accounts.google.com/signup"
driver.get(signup_url)# 填写姓名
wait.until(EC.visibility_of_element_located((By.NAME, "firstName"))).send_keys(first_name)
wait.until(EC.visibility_of_element_located((By.NAME, "lastName"))).send_keys(last_name)# 点击"下一步"按钮
next_button_xpath = "//button[.//span[contains(text(), 'Next') or contains(text(), '下一步')]]"
wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()
这里我们使用了两种元素定位方式:
- 通过NAME属性定位输入框
- 通过XPATH定位按钮,并兼容英文和中文界面
3. 填写生日和性别
# 选择月份
try:month_dropdown_element = wait.until(EC.element_to_be_clickable((By.ID, "month")))select_month = Select(month_dropdown_element)select_month.select_by_value(birth_month_value)
except TimeoutException:print("错误:在等待时间内未能找到或点击月份下拉框。")driver.save_screenshot('error_month_dropdown_timeout.png')raise
except NoSuchElementException:print("错误:DOM中不存在ID为'month'的元素。")driver.save_screenshot('error_month_dropdown_noelement.png')raise# 填写日期和年份
day_element = wait.until(EC.visibility_of_element_located((By.ID, "day")))
day_element.send_keys(birth_day)
year_element = wait.until(EC.visibility_of_element_located((By.ID, "year")))
year_element.send_keys(birth_year)# 选择性别
gender_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "gender")))
select_gender = Select(gender_dropdown)
select_gender.select_by_value(gender_value)# 点击"下一步"
wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()
这部分代码展示了:
- 如何使用Select类操作下拉框
- 如何进行异常处理并保存截图
- 如何使用ID定位元素
4. 选择Gmail地址
# 尝试定位"创建自己的Gmail地址"选项
try:create_own_radio_xpath = "//div[contains(text(), 'Create your own Gmail address')]/preceding-sibling::div//input[@type='radio']"wait.until(EC.element_to_be_clickable((By.XPATH, create_own_radio_xpath))).click()
except (TimeoutException, NoSuchElementException):print("未找到'创建自己的Gmail地址'单选按钮,假设可以直接输入用户名。")# 输入期望的用户名
username_input = wait.until(EC.visibility_of_element_located((By.NAME, "Username")))
username_input.send_keys(desired_username)# 点击"下一步"
wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()
这里展示了如何处理可能存在也可能不存在的元素,增强脚本的健壮性。
5. 设置密码
# 输入密码
password_input = wait.until(EC.visibility_of_element_located((By.NAME, "Passwd")))
password_input.send_keys(password)
confirm_password_input = wait.until(EC.visibility_of_element_located((By.NAME, "PasswdAgain")))
confirm_password_input.send_keys(password)# 点击"下一步"
wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()
6. 电话号码验证
# 检查是否可以跳过电话验证
skip_button_xpath = "//button[.//span[contains(text(), 'Skip') or contains(text(), '跳过')]]"
try:skip_button = driver.find_element(By.XPATH, skip_button_xpath)if skip_button.is_displayed() and skip_button.is_enabled():skip_button.click()else:raise NoSuchElementException
except NoSuchElementException:# 输入电话号码phone_input = wait.until(EC.visibility_of_element_located((By.ID, "phoneNumberId")))phone_input.send_keys(phone_number)# 点击"下一步"发送验证码wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()# 等待并输入验证码code_input_name = "code"wait.until(EC.visibility_of_element_located((By.NAME, code_input_name)))verification_code = input("请输入收到的6位Google验证码: ")driver.find_element(By.NAME, code_input_name).send_keys(verification_code)# 点击"验证"按钮verify_button_xpath = "//button[.//span[contains(text(), 'Verify') or contains(text(), '验证') or contains(text(), 'Next') or contains(text(), '下一步')]]"wait.until(EC.element_to_be_clickable((By.XPATH, verify_button_xpath))).click()
这部分代码展示了:
- 如何处理可能的跳过选项
- 如何与用户交互获取验证码
- 如何使用复杂的XPATH定位按钮
7. 处理后续步骤和同意条款
# 处理恢复邮箱步骤
try:wait.until(EC.element_to_be_clickable((By.XPATH, skip_button_xpath))).click()
except (TimeoutException, NoSuchElementException):try:wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()except (TimeoutException, NoSuchElementException):print("警告:未找到下一步按钮,流程可能已变化。")# 滚动到页面底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)# 点击"同意"按钮
agree_button_xpath = "//button[.//span[contains(text(), 'I agree') or contains(text(), '同意') or contains(text(), 'Create Account') or contains(text(), '创建帐号')]]"
wait.until(EC.element_to_be_clickable((By.XPATH, agree_button_xpath))).click()
这部分展示了:
- 如何使用JavaScript执行滚动操作
- 如何处理多语言界面的按钮
三、完整代码
import time
from selenium import webdriver
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.support.ui import Select
from selenium.common.exceptions import TimeoutException, NoSuchElementException# --- 配置 ---
# 将 'path/to/your/chromedriver' 替换为你的 ChromeDriver 实际路径
# 如果 chromedriver 在系统 PATH 中,可以简化为: driver = webdriver.Chrome()
#webdriver_path = 'path/to/your/chromedriver' # 例如: '/usr/local/bin/chromedriver' 或 'C:/webdrivers/chromedriver.exe'# --- 测试数据 (使用占位符,实际应安全管理) ---
first_name = "Franken"
last_name = "Markeron"
# Google 可能会建议用户名,或让你自己创建
desired_username = f"{first_name.lower()[:3]}{last_name.lower()[:3]}" # 创建一个独特的用户名尝试
password = "MyFrankPassword123!" # 使用强密码
birth_month_value = "1" # <--- 假设你要选择 1 月 (January)
birth_day = "1"
birth_year = "1995"
# 性别选项的值可能因语言和 Google 的更新而变化,需要检查页面元素
# 可能的值: 'Female', 'Male', 'Rather not say', 'Custom' (对应的 value 可能是 1, 2, 3, 4 或其他)
gender_value = "3" # 示例: 'Rather not say' (假设其 value 是 '3')# 电话号码 - 这是自动化的一大难点
# 你需要提供一个有效的、能接收短信的号码
phone_number = "YOUR_VALID_PHONE_NUMBER" # <--- 必须替换为真实有效的号码# --- WebDriver 初始化 ---
options = webdriver.ChromeOptions()
# 更新 User-Agent 为最新版本
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.7049.115 Safari/537.36")# 禁用自动化标志
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)# 添加新的反自动化检测参数
options.add_argument("--disable-blink-features=AutomationControlled")# 添加其他有用的配置
options.add_argument("--disable-notifications") # 禁用通知
options.add_argument("--disable-popup-blocking") # 禁用弹窗拦截
options.add_argument("--disable-infobars") # 禁用信息栏
options.add_argument("--start-maximized") # 启动时最大化窗口# 设置 CDP 命令以修改 webdriver 相关参数
options.add_argument("--remote-debugging-port=9222") # 开启调试端口# 使用 Service 对象指定路径 (推荐方式)
service = webdriver.ChromeService()
driver = webdriver.Chrome(service=service, options=options)wait = WebDriverWait(driver, 11) # 设置显式等待,最多等待 20 秒print("WebDriver 初始化完成。")try:# 1. 打开 Google 账号注册页面print("正在打开 Google 注册页面...")# 注意:URL 可能因地区而异,或 Google 可能更改入口signup_url = "https://accounts.google.com/signup"driver.get(signup_url)print("页面已加载。")# --- 填写姓名 ---print("正在填写姓名...")wait.until(EC.visibility_of_element_located((By.NAME, "firstName"))).send_keys(first_name)wait.until(EC.visibility_of_element_located((By.NAME, "lastName"))).send_keys(last_name)# 点击“下一步”按钮 (可能需要调整定位器)# Google 的按钮有时没有 name 或 id,需要 XPath 或 CSS Selector# 尝试 XPath: //button[.//span[contains(text(), 'Next')]] 或类似next_button_xpath = "//button[.//span[contains(text(), 'Next') or contains(text(), '下一步')]]" # 适配英文和中文 '下一步'wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("姓名填写完成,已点击下一步。")# --- 填写基本信息 (生日和性别) ---# --- Birth Month ---# !! 重要: 将月份改为对应的数字值 (1-12) !!# 例如: January -> "1", February -> "2", ..., December -> "12"#birth_month_value = "1" # <--- 假设你要选择 1 月 (January)try:# 等待下拉框元素变为可点击状态month_dropdown_element = wait.until(EC.element_to_be_clickable((By.ID, "month")))print("月份下拉框已找到且可点击。")# 创建 Select 对象select_month = Select(month_dropdown_element)# 使用 value 属性来选择月份print(f"尝试通过 value '{birth_month_value}' 选择月份...")select_month.select_by_value(birth_month_value)print(f"已选择月份,值为: {birth_month_value}")except TimeoutException:print(f"错误:在 {wait._timeout} 秒内未能找到或点击 ID 为 'month' 的月份下拉框。")print("请检查:")print("1. 页面是否已完全加载?")print("2. ID 'month' 是否仍然正确?(检查浏览器开发者工具)")print("3. 下拉框是否被其他元素遮挡?")print("4. 下拉框是否在 iframe 内?(如果是,需要先切换到 iframe)")driver.save_screenshot('error_month_dropdown_timeout.png')raise # 重新抛出异常,中断脚本except NoSuchElementException:print(f"错误:DOM 中不存在 ID 为 'month' 的元素。请确认定位器正确。")driver.save_screenshot('error_month_dropdown_noelement.png')raiseexcept Exception as e:print(f"选择月份时发生意外错误: {e}")driver.save_screenshot('error_month_dropdown_other.png')raise# --- Birth Day and Year (保持不变,但也要确保 ID 正确) ---try:day_element = wait.until(EC.visibility_of_element_located((By.ID, "day"))) # ID 可能会变day_element.send_keys(birth_day)year_element = wait.until(EC.visibility_of_element_located((By.ID, "year"))) # ID 可能会变year_element.send_keys(birth_year)print("日期和年份已填写。")except TimeoutException:print("错误:填写日期或年份的输入框未在预期时间内可见。请检查 ID 'day' 或 'year' 是否正确。")driver.save_screenshot('error_day_year_timeout.png')raiseexcept Exception as e:print(f"填写日期或年份时发生错误: {e}")driver.save_screenshot('error_day_year_other.png')raise# --- Gender (假设之前的逻辑可能有效,但同样需要检查) ---# ... (之前的性别选择代码) ...# 确保性别选择的定位器和值也与当前页面匹配try:gender_value = "3" # 示例: 'Rather not say' (假设其 value 是 '3')gender_dropdown = wait.until(EC.element_to_be_clickable((By.ID, "gender"))) # ID 可能会变select_gender = Select(gender_dropdown)select_gender.select_by_value(gender_value) # 假设我们知道 valueprint(f"已选择性别,值为: {gender_value}")except (TimeoutException, NoSuchElementException):print("警告:无法找到 ID 为 'gender' 的下拉框,尝试定位单选按钮或其他元素。")# 添加其他性别元素的处理逻辑...# 如果找不到性别元素也可能导致后续失败,需要健壮处理driver.save_screenshot('error_gender_not_found.png')# 根据你的测试需求决定是否在此处 raise 异常except Exception as e:print(f"选择性别时发生错误: {e}")driver.save_screenshot('error_gender_other.png')# 根据你的测试需求决定是否在此处 raise 异常# 点击“下一步”wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("生日和性别填写完成,已点击下一步。")# --- 选择 Gmail 地址 ---print("正在选择 Gmail 地址...")time.sleep(2) # 等待建议加载或输入框出现# Google 可能提供建议,或者让你创建自己的地址# 假设我们要创建自己的地址 (可能需要先点击某个选项)# 尝试定位 "Create your own Gmail address" 选项(如果存在)try:# 定位器需要根据实际页面调整create_own_radio_xpath = "//div[contains(text(), 'Create your own Gmail address')]/preceding-sibling::div//input[@type='radio']"wait.until(EC.element_to_be_clickable((By.XPATH, create_own_radio_xpath))).click()print("已选择 '创建自己的 Gmail 地址' 选项。")time.sleep(0.5)except (TimeoutException, NoSuchElementException):print("信息:未找到 '创建自己的 Gmail 地址' 单选按钮,假设可以直接输入用户名。")# 输入期望的用户名# 定位器通常是 name='Username' 或类似username_input = wait.until(EC.visibility_of_element_located((By.NAME, "Username"))) # Name 可能会变username_input.send_keys(desired_username)# 点击“下一步”wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print(f"尝试使用用户名 '{desired_username}',已点击下一步。")time.sleep(2) # 等待用户名检查结果# 检查用户名是否可用(可能会出现错误消息)# 你需要添加逻辑来处理用户名已被占用的情况(例如,查找错误提示元素)# --- 设置密码 ---print("正在设置密码...")# 定位器通常是 name='Passwd' 和 name='ConfirmPasswd'password_input = wait.until(EC.visibility_of_element_located((By.NAME, "Passwd")))password_input.send_keys(password)confirm_password_input = wait.until(EC.visibility_of_element_located((By.NAME, "PasswdAgain")))confirm_password_input.send_keys(password)# 可能有一个“显示密码”的复选框,可以忽略或根据需要交互# 点击“下一步”wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("密码设置完成,已点击下一步。")# --- !!! 电话号码验证 !!! ---# 这是自动化最难的部分,很可能会失败或需要人工干预print("进入电话号码验证阶段...")time.sleep(2) # 等待页面加载# 检查是否需要电话号码(有时可以跳过,但越来越少见)# 你需要检查页面上是否有 "Skip" 或 "跳过" 按钮skip_button_xpath = "//button[.//span[contains(text(), 'Skip') or contains(text(), '跳过')]]"try:skip_button = driver.find_element(By.XPATH, skip_button_xpath)if skip_button.is_displayed() and skip_button.is_enabled():print("找到'跳过'按钮,尝试跳过电话验证...")skip_button.click()print("已点击'跳过'。")else:raise NoSuchElementException # 如果按钮不可见或不可用,则认为需要输入号码except NoSuchElementException:print("未找到可用的'跳过'按钮,需要进行电话验证。")try:# 输入电话号码# 定位器可能是 ID 'phoneNumberId' 或其他phone_input_id = "phoneNumberId" # ID 极有可能变化,需要检查phone_input = wait.until(EC.visibility_of_element_located((By.ID, phone_input_id)))phone_input.send_keys(phone_number)print(f"已输入电话号码: {phone_number}")# 点击“下一步”发送验证码wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("已点击下一步,请求发送验证码。")# --- !!! 等待并输入验证码 (手动或外部服务) !!! ---print("\n" + "="*40)print("!!! 重要: Google 已发送验证码到你的手机 !!!")print("!!! 脚本现在暂停,请手动查看短信并在此处输入验证码。")print("="*40 + "\n")# 定位验证码输入框 (ID/Name 可能会变)code_input_name = "code" # 假设 name 是 'code'wait.until(EC.visibility_of_element_located((By.NAME, code_input_name))) # 等待输入框出现verification_code = input("请输入收到的 6 位 Google 验证码: ")driver.find_element(By.NAME, code_input_name).send_keys(verification_code)# 点击“下一步”或“验证”按钮verify_button_xpath = "//button[.//span[contains(text(), 'Verify') or contains(text(), '验证') or contains(text(), 'Next') or contains(text(), '下一步')]]" # 可能有不同文本wait.until(EC.element_to_be_clickable((By.XPATH, verify_button_xpath))).click()print("验证码已提交。")except (TimeoutException, NoSuchElementException) as e:print(f"错误:在电话验证阶段查找元素失败: {e}")print("自动化流程可能在此处中断。请检查页面元素定位器。")# 可以在这里加截图或其他调试信息driver.save_screenshot('error_phone_verification.png')raise # 重新抛出异常,中断脚本# --- 后续步骤 (可能包括添加恢复邮箱、同意条款等) ---print("处理后续步骤(恢复邮箱、条款等)...")time.sleep(3) # 等待下一页# 添加恢复邮箱(通常可以跳过)try:# 定位恢复邮箱输入框 (如果存在)# recovery_email_input = wait.until(EC.visibility_of_element_located((By.NAME, "recoveryEmail")))# 如果你想添加: recovery_email_input.send_keys("your_recovery_email@example.com")# 查找并点击 "Skip" 或 "跳过" 按钮# 注意:这里的按钮可能与电话验证的 Skip 按钮不同,检查 XPathskip_recovery_xpath = skip_button_xpath # 假设 XPath 相同,需要验证wait.until(EC.element_to_be_clickable((By.XPATH, skip_recovery_xpath))).click()print("已跳过添加恢复邮箱步骤。")except (TimeoutException, NoSuchElementException):print("信息:未找到恢复邮箱输入框或跳过按钮,可能流程已变化或直接进入下一步。")# 如果没找到跳过,可能需要点击 'Next'try:wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("未找到跳过,点击了下一步。")except (TimeoutException, NoSuchElementException):print("警告:也未找到下一步按钮,流程可能卡住或已变化。")time.sleep(2)# 添加电话号码(有时会再次询问,通常也可以跳过)try:# 查找并点击 "Skip" 或 "跳过" 按钮skip_add_phone_xpath = skip_button_xpath # 假设 XPath 相同,需要验证wait.until(EC.element_to_be_clickable((By.XPATH, skip_add_phone_xpath))).click()print("已跳过再次添加电话号码步骤。")except (TimeoutException, NoSuchElementException):print("信息:未找到再次添加电话号码的跳过按钮,可能流程已变化或直接进入下一步。")# 如果没找到跳过,可能需要点击 'Yes, I'm in' 或 'Next'try:# 定位器需要根据实际情况调整yes_im_in_button_xpath = "//button[.//span[contains(text(), 'Yes, I’m in')]]"wait.until(EC.element_to_be_clickable((By.XPATH, yes_im_in_button_xpath))).click()print("未找到跳过,点击了 'Yes, I’m in' 或类似按钮。")except (TimeoutException, NoSuchElementException):print("警告:也未找到 'Yes, I’m in' 或下一步按钮,流程可能卡住或已变化。")time.sleep(2)# 查看账户信息(确认页面)try:print("正在查看账户信息确认页面...")wait.until(EC.element_to_be_clickable((By.XPATH, next_button_xpath))).click()print("已确认账户信息,点击下一步。")except (TimeoutException, NoSuchElementException):print("警告:未找到账户信息确认页面的下一步按钮,流程可能已变化。")# --- 同意隐私政策和条款 ---print("正在处理隐私政策和条款...")time.sleep(3) # 等待页面完全加载,特别是底部的按钮# 需要滚动到底部才能使“同意”按钮可点击print("滚动到页面底部...")driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")time.sleep(1) # 等待滚动完成# 点击“同意”或“创建账户”按钮# 定位器可能变化,文本可能是 'I agree', 'Create Account', '同意', '创建帐号' 等agree_button_xpath = "//button[.//span[contains(text(), 'I agree') or contains(text(), '同意') or contains(text(), 'Create Account') or contains(text(), '创建帐号')]]"try:wait.until(EC.element_to_be_clickable((By.XPATH, agree_button_xpath))).click()print("已同意条款并点击创建账户按钮。")except (TimeoutException, NoSuchElementException) as e:print(f"错误:无法找到或点击同意按钮: {e}")driver.save_screenshot('error_agreement.png')raise# --- 注册完成 ---# 等待跳转到 Google 欢迎页面或仪表板print("等待注册完成并跳转...")# 等待某个明确的、注册成功后才会出现的元素,例如账户图标或欢迎信息# 例如,等待右上角的账户图标 (aria-label 可能包含姓名或邮箱)try:account_icon_xpath = f"//a[contains(@aria-label, '{first_name}') or contains(@aria-label, '{desired_username}')]"wait.until(EC.visibility_of_element_located((By.XPATH, account_icon_xpath)))print("\n" + "="*40)print(">>> Google 账号注册成功! <<<")print(f"用户名: {desired_username}@gmail.com")print(f"密码: {password}")print("="*40)# 可以在这里加截图driver.save_screenshot('registration_success.png')except TimeoutException:print("错误:注册似乎已完成,但无法在目标页面上找到预期的确认元素。")print("请手动检查浏览器状态。")driver.save_screenshot('registration_maybe_finished.png')# 保持浏览器打开几秒钟以便观察print("测试脚本执行完毕,浏览器将在一分钟后关闭...")time.sleep(60)except Exception as e:print(f"\n--- 脚本执行过程中发生错误 ---")print(e)# 尝试截屏记录错误发生时的状态try:timestamp = time.strftime("%Y%m%d-%H%M%S")error_screenshot_path = f'error_screenshot_{timestamp}.png'driver.save_screenshot(error_screenshot_path)print(f"错误截图已保存至: {error_screenshot_path}")except Exception as screen_err:print(f"尝试截屏时也发生错误: {screen_err}")finally:# --- 清理 ---if 'driver' in locals() and driver:print("正在关闭 WebDriver...")driver.quit()print("WebDriver 已关闭。")
四、技术要点总结
-
元素定位技巧
- 使用多种定位方式:ID、NAME、XPATH
- 构建健壮的XPATH表达式,兼容多语言界面
- 处理动态变化的元素
-
等待策略
- 使用显式等待提高脚本稳定性
- 合理设置等待条件和超时时间
-
异常处理
- 捕获并处理常见异常:TimeoutException、NoSuchElementException
- 保存错误截图便于调试
-
交互技巧
- 处理表单输入
- 操作下拉框
- 执行JavaScript脚本
- 与用户交互获取验证码
-
反自动化检测
- 设置合适的User-Agent
- 禁用自动化标志
- 添加反检测参数
五、声明
以上内容仅供学习,请勿用于其他用途;因此产生的纠纷与本人无关。
本文通过Google注册流程的自动化案例,详细讲解了Selenium的高级用法。希望这个实例能帮助你更好地理解和掌握Selenium自动化测试技术。如有问题,欢迎在评论区留言讨论!
相关文章:
自动化实现web端Google SignUp——selenium
案例:自动化获取Google注册页面——selenium 前言 提示:通过案例掌握selenium语法 涉及技术:Python Selenium 在本文中,我们将通过一个实际案例来学习如何使用Selenium自动化工具模拟Google账号注册流程。这个案例涵盖了Selen…...
如何阅读GitHub上的深度学习项目
一、前期准备:构建知识基础 1. 必备工具与环境 开发工具: IDE:VS Code(推荐,轻量化插件丰富,如 Python、PyTorch 插件)、PyCharm(适合大型项目)。版本控制:…...
【LeetCode 热题 100】3.无重复字符的最长子串:详解滑动窗口解法
📌 原题链接:Longest Substring Without Repeating Characters 📖 一、题目描述 给定一个字符串 s,请你找出其中不含有重复字符的最长子串的长度。 示例: 输入: s "abcabcbb" 输出: 3 解释: 最长不重复子…...
Android12 Rom定制设置默认语言为中文
Android12 Rom定制设置默认语言为中文 1.前言: 最近在做客制化定制时需要默认语言为中文,而且可以切换输入法,之前讲解过在ROM中如何设置默认输入法,这里就不展开了,其实这个需求很简单,就是调试的时候发现…...
【设计模式】GoF设计模式之备忘录模式(Memento Pattern)
设计模式之备忘录模式 Memento Pattern V1.0核心概念角色代码示例程序运行结果代码讲解 适用场景 V1.0 核心概念 备忘录模式的核心是定义一个备忘录类(Memento),这个类的实例能够表示发起人类(Originator)的一种状态…...
springboot分层打包,减少重复构建和传输的开销
在 Spring Boot 中,分层打包(Layered Packaging) 是一种优化策略,特别针对 容器化部署(如 Docker) 的场景设计。它的核心思想是将应用的不同部分(依赖、资源、代码等)划分为独立的层…...
Linux——虚拟地址空间
1.虚拟地址空间 进程地址空间又叫虚拟地址空间 我们大家知道程序在运行时使用的空间被划分为多个不同的区域,每个区域都有不同的作用 正文代码:存放程序的可执行代码 通常都是只读的初始化数据:未初始化数据堆区:用于动态分配内存…...
GPU虚拟化实现(七)
GPU虚拟化实现(七) 章节回顾进程管理资源限制和环境变量利用率监控线程信号处理退出处理代码具体运作流程怎么限制SM的总结章节回顾 在上一章,分析了项目的主要代码模块功能:共享内存和初始化、GPU 内存管理、GPU 利用率管理以及锁机制,在这一章将继续分析其他的代码模块…...
【QNX+Android虚拟化方案】137 - msm-5.4 Kernel U盘 插入中断、枚举、匹配完整流程详解
【QNX+Android虚拟化方案】137 - msm-5.4 Kernel U盘 插入中断、枚举、匹配完整流程详解 1. HUB提交中断URB给HCD控制器,URB完成回调函数为 hub_irq()2. U盘插入后,触发运行 hub_irq() 中断回调函数2.1 高通 DWC3 Host HCD 初始化流程2.2 urb->complete(urb) 中断回调流程…...
分布式锁的几种实现
前几天看一个面试视频,提到了分布式锁一直想写写,但奈何考试太多,直到今天才有时间。好啦,开始今天的文章吧。 一.定义 分布式锁:当多个进程不在同一个系统中(比如分布式系统中控制共享资源访问),用分布式…...
Android 解绑服务问题:java.lang.IllegalArgumentException: Service not registered
问题与处理策略 问题描述 在 Android 项目中,解绑(unbindService())一个服务(Service)时,报如下错误 java.lang.IllegalArgumentException: Service not registered问题原因 错误表明在解绑服务时&…...
注册登录页面项目
关系型数据库地址:C:\Users\ASUS\AppData\Local\Temp\HuaweiDevEcoStudioDatabases\rdb #注册页面register.ets import dataRdb from ohos.data.rdbconst STORE_CONFIG {name: weather4.db } const TABLE_NAME weather_info const SQL_CREATE_TABLE CREATE TAB…...
从 Python 基础到 Django 实战 —— 数据类型驱动的 Web 开发之旅
主题简介: 本主题以 Python 基础数据类型为核心,结合 Django 框架的开发流程,系统讲解如何通过掌握数字、字符串、列表、元组、字典等基础类型,快速构建功能完善的 Web 应用。通过理论与实践结合,帮助学员从零基础 Py…...
数字智慧方案5971丨智慧农业大数据平台解决方案(59页PPT)(文末有下载方式)
详细资料请看本解读文章的最后内容。 资料解读:智慧农业大数据平台解决方案 在现代农业发展进程中,智慧农业大数据平台解决方案正成为推动农业变革的关键力量。这一方案从项目简介到大数据展示,各个环节紧密相连,致力于为农业发展…...
MOOS-ivp使用(一)——水下机器人系统的入门与使用
MOOS-ivp使用(一)——水下机器人系统的入门与使用 MOOS-ivp(Marine Operational Oceanographic System for Intelligent Vehicle Planning)是专为水下机器人(如AUV)设计的开源框架。类似于ROS,…...
【网络服务器】——回声服务器(echo)
作用 实现回声服务器的客户端/服务器程序,客户端通过网络连接到服务器,并发送任意一串英文信息,服务器端接收信息后,执行数据处理函数:将每个字符转换为大写并回送给客户端显示。 客户端:发送字符信息 服…...
IDEA在项目中添加模块出现Error adding module to project: null(向项目添加模块时出错: null)的解决方法
解决方法 (1)打开当前项目的结构...
(34)VTK C++开发示例 ---将图片映射到平面
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 演示如何将图片作为纹理贴图到一个平面上。 这段代码的功能是使用 VTK(Visualization Toolkit࿰…...
微软与Meta大幅增加人工智能基础设施投入
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
华为云服务器VoceChat在线聊天室部署
目录 1. 项目介绍2. 准备条件3. Docker环境部署3.1 安装Docker(CentOS 7)3.2 安装Docker Compose3.3 Docker常用命令 4. 创建配置文件4.1 创建工作目录4.2 创建docker-compose.yml文件4.3 保存配置文件 5. 部署运行5.1 启动服务5.2 检查服务状态5.3 防火…...
ERP系统(技术面)知识积累
本文为本人在准备某公司信息技术类岗位的面试时所作的笔记,该公司有技术面,此岗位入职后负责的是ERP系统的运行和维护,所以可能会问ERP系统相关的问题。故我写此文以做准备。 ERP简介 ERP,全称Enterprise Resource Planning&…...
Python学习笔记(第三部分)
接续 Python.md 文件的第三部分 类 类的创建的基本使用 创建一个类 class Dog(): 文档字符串:这是一次模拟小狗的简单尝试 def __init__(self,name,age):self.name nameself.age agedef sit(self):print(self.name.title() " is now sitting.")def ro…...
【浅尝Java】Java简介第一个Java程序(含JDK、JRE与JVM关系、javcdoc的使用)
🍞自我激励:每天努力一点点,技术变化看得见 文章目录 Java语言概述Java是什么Java语言的重要性Java语言发展简史Java语言特性 第一个Java程序main方法示例运行Java程序JDK、JRE、JVM之间的关系注释基本规则注释规范 标识符关键字 Java语言概述…...
【FreeRTOS-列表和列表项】
参照正点原子以及以下gitee笔记整理本博客,并将实验结果附在文末。 https://gitee.com/xrbin/FreeRTOS_learning/tree/master 一、列表和列表项的简介(熟悉) 1、什么是列表 答:列表是FreeRTOS中的一个数据结构,概念上和链表有点类似&#…...
22.2Linux的I2C驱动实验(编程)_csdn
我尽量讲的更详细,为了关注我的粉丝!!! 这里我们用到的是stm32mp157的板子,所以我们看一下I2C用到的引脚。 1、硬件原理图分析 可以看到在这块板子上面用的SDA和SCL总线是PA11,PA12。所以要修改设备树和镜像文件&…...
socket-IO复用技术
五个I/O模型 1、阻塞I/O 2、非阻塞I/O 3、I/O复用(select和poll) 4、信号驱动I/O 5、异步I/O I/O复用 是一种在单线程或单进程环境下,同时监听多个 I/O 事件的技术。它允许程序高效地处理多个输入输出流(如网络套接字、文件描…...
上位机知识篇---二进制操作
文章目录 前言接收数据示例:0xAA 0x12 0x34 0x55合并高/低字节数据RGB565颜色值:0xF800(红色)Python中负数右移接收帧:01 03 02 12 34 CRC前言 本文简单对单片机、上位机中的映射(Mapping)和位移操作符(Bit Shifting)等相关知识进行了简单介绍. 一、单片机与上位机中…...
openEuler 22.03 安装 Mysql 5.7,TAR离线安装
目录 一、检查系统是否安装其他版本Mariadb数据库二、环境检查2.1 必要环境检查2.2 在线安装(有网络)2.3 离线安装(无网络) 二、下载Mysql2.1 在线下载2.2 离线下载 三、安装Mysql四、配置Mysql五、开放防火墙端口六、数据备份七、…...
《排序算法总结》
引言: 编程学到现在,我们已经接触了很多种排序算法,这篇文章我就对常见的几种排序算法进行一个小结。 一: 排序算法分类: 二: 插入排序: 直接插入排序: 1. 概念: 直…...
【Java学习笔记】递归
递归(recursion) 思想:把一个复杂的问题拆分成一个简单问题和子问题,子问题又是更小规模的复杂问题,循环往复 本质:栈的使用 递归的注意事项 (1)需要有递归出口,否者就…...
体系学习1:C语言与指针1——预定义、进制打印、传参为数组
1、不对一段代码进行编译 #if 0 statement #endif2、输出地址 int d[3]{1,2,3}; printf("%p",(void*)d);//p期待的是void*类型的数据3、不同进制的打印 int data 1200; char hed[9];//为\0预留位置!!! sprintf(hed,"%08X&…...
使用Java正则表达式进行分组与匹配文本提取
在Java开发中,正则表达式(Regex)是处理字符串的强大工具,广泛应用于数据验证、文本解析和格式转换等场景。通过正则表达式的分组功能,开发者可以精确地提取匹配模式的子部分,而不仅仅是整个匹配内容。Java的…...
RAGFlow上传3M是excel表格到知识库,提示上传的文件总大小过大
环境: Ragflowv0.17.2 问题描述: RAGFlow上传3M是excel表格到知识库,提示上传的文件总大小过大 解决方案: 定位问题: 1.查询Nginx 日志 Nginx 日志 检查 Nginx 配置中日志路径是否正确,确保日志文件有…...
2025年4月文章一览
2025年4月编程人总共更新了30篇文章: 1.2025年3月文章一览 2.《Operating System Concepts》阅读笔记:p528-p544 3.《Operating System Concepts》阅读笔记:p545-p551 4.《Operating System Concepts》阅读笔记:p552-p579 5.…...
2025大模型微调视频课程全套(附下载)
2025大模型微调视频课程全套,共10课。主要内容如下: 1、大模型的发展 2、Transformer & LLMs 3、大模型微调预览&Lora微调&Alpaca模型微调 4、Alpaca&AdaLoRA&QLoRA模型微调 5、Efficient Fine-tuning&Efficient Inference&…...
【Python Web开发】04-Cookie和Session
文章目录 1. Cookie1.1 定义1.2 工作原理1.3 用途1.4 优缺点 2. Session2.1 定义2.2 工作原理2.3 用途2.4 优缺点 3. Cookie 与 Session 的关系4. 安全性考量5. Python 中使用 Cookie 和 Session 在 HTTP 协议里,Cookie 和 Session 是用于管理客户端与服务器之间会话…...
从股指到期指,哪些因素影响基差?
当我们谈论股指期货(简称“期指”)与股票现货指数(简称“股指”)的基差时,其实是在探讨期货价格与现货价格之间的“差价”。这个差价受多种因素影响,时而扩大,时而缩小,甚至可能“翻…...
n8n 中文系列教程_15. 【工具篇】n8n中文版与汉化指南:从原理到实践
n8n 作为一款强大的开源自动化工具,目前尚未推出官方中文版,但社区提供了汉化方案。不过,对于技术用户,我们更推荐使用英文原版,以便更好地查阅文档和解决问题。如果你仍希望尝试汉化,本文将详细介绍如何通…...
3D版同步帧游戏
以下是实现一个3D版同步帧游戏的详细步骤与完整代码示例。我们将以第一人称射击游戏(FPS)为原型,重点讲解3D空间中的同步机制优化。 项目升级:3D版核心改动 1. 3D坐标系与消息结构 // common/messages.go type Vector3 struct {X float32 `json:"x"`Y float32 `…...
C语言中数字转化为字符串的方法
C语言中数字转化为字符串的方法 1. 使用 sprintf 函数 这是 stdio.h 头文件中的标准库函数 ,功能类似于 printf ,但不是输出到控制台,而是将格式化后的内容输出到字符数组(字符串)中。 示例代码: c #inc…...
使用MGeo模型高精度实现文本中地址识别
一、功能与安装 1、模型地址 模型是阿里开发的门址高精度识别模型。 https://modelscope.cn/models/iic/mgeo_geographic_elements_tagging_chinese_base/summary 注意:不能自己安装包,没法解决依赖问题,直接按照官方要求安装下面的包&am…...
OpenGL-ES 学习(15) ----纹理
目录 纹理简介纹理映射纹理映射流程示例代码:纹理的环绕和过滤方式纹理的过滤方式 纹理简介 现实生活中,纹理(Texture) 类似于游戏中皮肤的概念,最通常的作用是装饰 3D 物体,它像贴纸一样贴在物体的表面,丰富物体的表…...
类成员函数编译链接的过程
1.静态成员函数和普通成员函数 源文件编译成目标文件,静态成员函数和普通成员函数在目标文件代码段,函数添加进了符号表,地址是在代码段的相对地址,这个地址只是一个临时地址因为后面链接时还要合并代码段,函数地址还…...
PostgreSQL:pgAdmin 4 使用教程
pgAdmin 4 是一个用于管理和维护 PostgreSQL 数据库的强大工具。它提供了一个图形化界面,使用户能够轻松地连接到数据库、创建表、运行 SQL 语句以及执行其他数据库管理任务。 安装和使用 安装 pgAdmin 4 安装 pgAdmin 4 非常简单。下载并运行安装程序࿰…...
*(解引用运算符)与 ++(自增运算符)的优先级
在 C 和 C 等编程语言里,*(解引用运算符)与 (自增运算符)的执行优先级高低,要依据 是前缀形式还是后缀形式来确定。下面为你详细分析: 1. 后缀 运算符 后缀 运算符的优先级比 *(…...
二叉搜索树中的搜索(递归解决)
700. 二叉搜索树中的搜索 - 力扣(LeetCode) 二叉搜索树(BST):以任意节点为根节点的数值大于其左子树所有节点的值,小于右子树所有节点的值。 查找二叉搜索树中的值,要利用节点之间的大小关系。…...
idea安装
1.卸载 2.安装 3.ssh...
在ASP.NET MVC中使用Repeater指南
虽然ASP.NET MVC框架本身不包含Web Forms中的Repeater控件,但您可以通过几种方式实现类似的功能。以下是几种在MVC中实现Repeater效果的方法: 1. 使用foreach循环 最简单的方法是直接在视图中使用Razor的foreach循环: csharp model IEnumer…...
【C语言常用字符串解析】
总结一下在 C 语言中用于字符串解析(特别是从文件中读取行并提取数据)的常用函数、 核心任务: 通常是从文件中读取一行文本(一个字符串),然后从这个字符串中提取出需要的数据(比如数字、单词等…...
基于深度学习农作物叶部病害实时检测系统研究(源码+定制+开发)
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...