Playwright+DeepSeek做AI自动化测试:一个能跑的入门方案
Playwright+DeepSeek做AI自动化测试:一个能跑的入门方案
用Playwright截图发给DeepSeek大模型,让它分析页面结构并生成测试步骤,Playwright再自动执行——试了一下发现可行,写出来给有同样需求的人参考。
起因
项目要做回归测试,打开Selenium脚本一看,30多个用例,一半的元素定位器失效了。前端改了class名,脚本就得跟着改,改了一下午。当时想,大模型能"看"图片,能不能让它帮我分析页面、生成测试步骤?折腾了两天,用Playwright+DeepSeek搭了个能跑的原型。
为什么选Playwright
Selenium的选择器策略比较单一,主要靠CSS Selector和XPath,前端一改就挂。Playwright支持by text、by role等语义化定位,API也更现代(微软维护)。但定位器脆弱这个问题,Playwright也没完全解决。
所以我试了另一个方向:把页面截图丢给大模型,让它告诉我"点哪里、输入什么"。
实现思路
流程分三步:
- Playwright打开页面,截图
- 截图发给DeepSeek,返回JSON格式的测试步骤
- Playwright按步骤执行
好处是,前端改了UI之后,大模型会根据新截图重新理解页面,不用手动改定位器。
环境准备
pip install playwright openai python-dotenv
playwright install chromium
去 platform.deepseek.com 注册拿个API Key,新用户有免费额度。建一个 .env 文件:
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxx
完整代码
import os
import json
import base64
from playwright.sync_api import sync_playwright
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com"
)
def analyze_page(image_path, task_desc):
"""截图发给大模型,返回测试步骤JSON"""
with open(image_path, "rb") as f:
img_b64 = base64.b64encode(f.read()).decode()
resp = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个测试工程师。根据页面截图和任务描述,生成JSON格式的测试步骤。"},
{"role": "user", "content": [
{"type": "text", "text": f"任务:{task_desc}\n\n请分析这个页面,生成测试步骤。"
"返回JSON数组,每个步骤包含action(type/click/press)、"
"target(页面上的文字描述)、value(需要输入的内容或按键名)。"
"只返回JSON,不要其他内容。"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}}
]}
],
temperature=0.3,
max_tokens=2000
)
text = resp.choices[0].message.content.strip()
# DeepSeek有时会套markdown代码块
if text.startswith("```"):
text = text.split("\n", 1)[1]
text = text.rsplit("```", 1)[0]
return json.loads(text)
def execute_steps(page, steps):
"""按大模型生成的步骤执行操作"""
results = []
for i, step in enumerate(steps):
action = step.get("action", "click")
target = step.get("target", "")
value = step.get("value", "")
try:
if action == "type":
locator = page.get_by_placeholder(target)
if locator.count() == 0:
locator = page.get_by_label(target)
if locator.count() == 0:
locator = page.get_by_role("textbox", name=target)
locator.first.fill(value)
results.append(f" [PASS] 步骤{i+1}: 在'{target}'输入'{value}'")
elif action == "click":
locator = page.get_by_role("button", name=target)
if locator.count() == 0:
locator = page.get_by_text(target)
if locator.count() == 0:
locator = page.locator(f"a:has-text('{target}')")
locator.first.click()
results.append(f" [PASS] 步骤{i+1}: 点击'{target}'")
elif action == "press":
# 按键前先聚焦到文本输入框,避免键盘事件发到错误元素
page.locator(
"input[type='text'], input[type='search'], textarea"
).first.focus()
page.keyboard.press(value)
results.append(f" [PASS] 步骤{i+1}: 按键'{value}'")
else:
results.append(f" [SKIP] 步骤{i+1}: 未知动作'{action}'")
except Exception as e:
results.append(f" [FAIL] 步骤{i+1}: {action} '{target}' - {e}")
return results
def run_test(url, task_desc, screenshot_dir="screenshots"):
os.makedirs(screenshot_dir, exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 1280, "height": 720})
print(f"打开页面: {url}")
page.goto(url, wait_until="networkidle")
ss_path = os.path.join(screenshot_dir, "page.png")
page.screenshot(path=ss_path)
print(f"截图已保存: {ss_path}")
print("正在分析页面...")
steps = analyze_page(ss_path, task_desc)
print(f"生成 {len(steps)} 个测试步骤:")
for i, s in enumerate(steps):
print(f" {i+1}. {s}")
print("\n执行测试:")
results = execute_steps(page, steps)
for r in results:
print(r)
result_path = os.path.join(screenshot_dir, "result.png")
page.screenshot(path=result_path)
browser.close()
passed = sum(1 for r in results if "[PASS]" in r)
failed = sum(1 for r in results if "[FAIL]" in r)
print(f"\n结果: {passed} passed, {failed} failed")
return results
if __name__ == "__main__":
run_test(
url="https://www.baidu.com",
task_desc="在百度搜索框输入'Playwright自动化测试',点击搜索按钮,验证搜索结果页包含搜索关键词"
)
运行
python ai_test.py
输出大概长这样:
打开页面: https://www.baidu.com
截图已保存: screenshots/page.png
正在分析页面...
生成 3 个测试步骤:
1. {'action': 'type', 'target': '请输入', 'value': 'Playwright自动化测试'}
2. {'action': 'click', 'target': '百度一下', 'value': ''}
3. {'action': 'press', 'value': 'Enter'}
执行测试:
[PASS] 步骤1: 在'请输入'输入'Playwright自动化测试'
[PASS] 步骤2: 点击'百度一下'
[PASS] 步骤3: 按键'Enter'
结果: 3 passed, 0 failed
screenshots目录下会生成page.png(执行前)和result.png(执行后)。
踩坑
大模型返回的JSON套了markdown代码块。 DeepSeek有时候会把JSON包在json...里,直接json.loads()会炸。代码里做了处理,先strip掉代码块标记再解析。如果模型返回格式更离谱(比如前面加了一段解释文字),建议加重试。
元素定位要多层fallback。 大模型说的target不一定精确——它说"搜索按钮",页面上写的是"百度一下"。所以execute_steps里做了三级fallback:先按role找,再按text找,最后用CSS选择器兜底。实测百度这种简单页面没问题,复杂页面(多个同名按钮、iframe嵌套)可能需要额外处理。
headless模式下动态内容可能还没加载完。 page.goto加了wait_until=“networkidle”,但如果页面有懒加载图片或延迟渲染的组件,截图时可能截不到。这种情况加一行就行:
page.wait_for_timeout(2000)
局限性
这个方案是个原型,离生产可用还有距离。几个问题:
- 每次测试都调API,有成本。DeepSeek便宜但跑大量用例费用会上来
- 大模型输出有一定随机性,同一个页面不同次可能生成不同步骤
- 只能处理单页面操作,涉及多页面跳转或复杂弹窗的场景没覆盖
如果想往生产用,可以考虑加步骤缓存(同样的页面不重复分析)、结果校验(截图对比)、失败重试这些。
参考
- Playwright Python文档:https://playwright.dev/python/
- DeepSeek API文档:https://platform.deepseek.com/api-docs
- OpenAI Python SDK:https://github.com/openai/openai-python
标签:AI应用、自动化测试、Playwright、Python、AI实战
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)