Playwright实现自动化

一、前言

        在当今的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自动化场景,如数据抓取、表单填写、功能测试等。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容