一、前言
在当今的Web开发和测试领域,自动化技术已经成为提高效率的必备工具。本文将介绍如何使用Playwright这一强大的自动化测试工具,实现一个完整的网站登录流程。我们将从环境配置开始,逐步深入到代码实现,最终完成一个可复用的自动化登录脚本。
二、准备阶段
在开始之前,我们需要确保开发环境已经准备就绪:
Python环境:建议使用Python 3.7及以上版本
Playwright安装:
pip install playwright
playwright install
浏览器驱动:Playwright支持Chromium、Firefox和WebKit,本文以Chromium为例
三、代码解析
3.1、基础配置
python
import os
import logging
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler()]
)
- 日志配置:使用Python内置的logging模块记录操作日志,便于调试和问题追踪
- 异常处理:特别处理Playwright的超时异常,确保脚本的健壮性
3.2、核心类设计
python
class PlaywrightAutomation:
def __init__(self, headless=True):
self.playwright = None
self.browser = None
self.page = None
self.headless = headless
self._install_browser()
- headless模式:默认为True表示无头模式,适合服务器环境;开发时可设为False便于观察
- 自动安装浏览器:在初始化时自动检查并安装必要的浏览器组件
3.3、 浏览器初始化
python
def init_browser(self):
try:
self.playwright = sync_playwright().start()
self.browser = self.playwright.chromium.launch(headless=self.headless)
self.page = self.browser.new_page()
logging.info("浏览器初始化成功")
return True
except Exception as e:
logging.error(f"浏览器初始化失败: {str(e)}")
return False
- 使用Chromium作为默认浏览器
- 完善的异常处理确保初始化失败时程序不会崩溃
3.4、元素等待机制
python
def _wait_for_element(self, selector, timeout=10000, clickable=False):
try:
if clickable:
self.page.wait_for_selector(selector, state="attached", timeout=timeout)
return self.page.wait_for_selector(selector, state="visible", timeout=timeout)
return self.page.wait_for_selector(selector, timeout=timeout)
except PlaywrightTimeoutError:
logging.error(f"元素定位超时: {selector}")
raise
- 支持两种等待模式:普通等待和可点击等待
- 默认10秒超时时间,可根据实际网络状况调整
- 详细的错误日志帮助快速定位问题
3.5、 登录功能实现
python
def login(self, login_url):
if not self.init_browser():
return False
try:
username = os.getenv("YOUUSER")
password = os.getenv("YOUPWD")
self.page.goto(login_url)
self.page.set_viewport_size({"width": 1920, "height": 1080})
# 元素定位器
user_selector = "input[type='text'][placeholder='登录名或手机号']"
pwd_selector = "input[type='password']"
login_btn_selector = "[class*='loginButton'] button"
checkbox_selector = "input[type='checkbox']"
# 填写表单
username_field = self._wait_for_element(user_selector)
password_field = self._wait_for_element(pwd_selector)
checkbox_field = self._wait_for_element(checkbox_selector)
username_field.fill("")
username_field.fill(username)
password_field.fill("")
password_field.fill(password)
if not checkbox_field.is_checked():
checkbox_field.click()
# 截图保存
self.page.screenshot(path="login_user_pwd.png")
# 提交登录
login_button = self._wait_for_element(login_btn_selector, clickable=True)
login_button.click()
return True
except Exception as e:
# 错误处理和截图
self.page.screenshot(path="login_error.png")
return False
- 从环境变量获取敏感信息,避免硬编码
- 自动调整视口大小确保页面元素正常显示
- 关键步骤截图保存,便于后续分析
- 全面的异常处理和日志记录
3.6、资源清理
python
def close(self):
if self.browser:
self.browser.close()
if self.playwright:
self.playwright.stop()
logging.info("浏览器已关闭")
- 确保浏览器和Playwright实例被正确关闭
- 防止资源泄漏
3.7、完整代码示例
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Users: LiMu
# @Files:login_playwright.py
# @Times: 2025/6/25
# @Software:PyCharm
import os
import logging
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
# 配置日志
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.StreamHandler()]
)
class PlaywrightAutomation:
def __init__(self, headless=True):
self.playwright = None
self.browser = None
self.page = None
self.headless = headless
self._install_browser()
def _install_browser(self):
"""安装必要的浏览器"""
os.system("playwright install chromium")
os.system("playwright install --dry-run")
def init_browser(self):
"""初始化浏览器和页面"""
try:
self.playwright = sync_playwright().start()
self.browser = self.playwright.chromium.launch(headless=self.headless)
self.page = self.browser.new_page()
logging.info("浏览器初始化成功")
return True
except Exception as e:
logging.error(f"浏览器初始化失败: {str(e)}")
return False
def _wait_for_element(self, selector, timeout=10000, clickable=False):
"""
等待元素出现或可点击
:param selector: 选择器
:param timeout: 超时时间(毫秒)
:param clickable: 是否要求元素可点击
:return: ElementHandle
"""
try:
if clickable:
self.page.wait_for_selector(selector, state="attached", timeout=timeout)
return self.page.wait_for_selector(selector, state="visible", timeout=timeout)
return self.page.wait_for_selector(selector, timeout=timeout)
except PlaywrightTimeoutError:
logging.error(f"元素定位超时: {selector}")
raise
except Exception as e:
logging.error(f"等待元素时发生错误: {str(e)}")
raise
def login(self, login_url):
"""执行登录操作"""
if not self.init_browser():
return False
try:
username = os.getenv("YOUUSER")
password = os.getenv("YOUPWD")
self.page.goto(login_url)
self.page.set_viewport_size({"width": 1920, "height": 1080})
logging.info("已打开登录页面")
# 定位元素选择器
user_selector = "input[type='text'][placeholder='登录名或手机号']"
pwd_selector = "input[type='password']"
login_btn_selector = "[class*='loginButton'] button"
checkbox_selector = "input[type='checkbox']"
# 等待元素并操作
username_field = self._wait_for_element(user_selector)
password_field = self._wait_for_element(pwd_selector)
checkbox_field = self._wait_for_element(checkbox_selector)
# 清空并输入用户名密码
username_field.fill("")
username_field.fill(username)
password_field.fill("")
password_field.fill(password)
# 判断并勾选复选框
if not checkbox_field.is_checked():
checkbox_field.click()
logging.info("已填写用户名和密码")
self.page.screenshot(path="login_user_pwd.png")
# 点击登录按钮
login_button = self._wait_for_element(login_btn_selector, clickable=True)
login_button.click()
logging.info("登录请求已提交")
return True
except PlaywrightTimeoutError as e:
logging.error(f"登录超时: {str(e)}")
self.page.screenshot(path="login_timeout.png")
return False
except Exception as e:
logging.error(f"登录过程中出错: {str(e)}")
self.page.screenshot(path="login_error.png")
return False
def close(self):
"""关闭浏览器"""
if self.browser:
self.browser.close()
if self.playwright:
self.playwright.stop()
logging.info("浏览器已关闭")
if __name__ == "__main__":
automation = PlaywrightAutomation(headless=False) # 设置为False可以看到浏览器操作
try:
automation.login("https://sh.***xt.com/account/login")
finally:
input("按回车键退出浏览器...")
automation.close()
四、最佳实践建议
4.1、选择器策略:
- 优先使用属性选择器而非类名,因为类名可能经常变化
- 对于动态内容,考虑使用XPath或文本匹配
4.2、等待优化:
- 根据实际网络状况调整超时时间
- 对于AJAX加载的内容,可以使用page.wait_for_function
4.3、安全考虑:
- 敏感信息如密码应通过环境变量传递
- 考虑使用dotenv加载本地.env文件
4.4、扩展功能:
- 添加验证码识别模块(如需要)
- 实现多账号轮换登录
- 添加登录成功后的跳转验证
4.5、常见问题解决
4.5.1、元素定位失败:
- 检查页面是否完全加载
- 验证选择器是否正确
- 尝试增加等待时间
4.5.2、浏览器无法启动:
- 确认Playwright浏览器已正确安装
- 检查防火墙设置是否阻止了浏览器启动
4.5.3、登录失败:
- 检查账号密码是否正确
- 查看网络请求是否被拦截
- 分析保存的错误截图
五、结语
本文详细介绍了如何使用Playwright实现自动化登录功能。通过合理的代码结构和完善的错误处理,我们构建了一个健壮、可维护的自动化脚本。这种技术不仅可以应用于登录功能,还可以扩展到各种Web自动化场景,如数据抓取、表单填写、功能测试等。