python使用playwright从入门到精通
·
安装playwright
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple playwright
playwright install
案例代码1
通过执行命令录取百度高级搜索生成脚本,调整脚本进行百度高级搜索
import re
import time
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://www.baidu.com/")
page.locator("#s-usersetting-top").hover()
page.get_by_role("link", name="高级搜索").click()
page.locator("#adv_keyword").click()
page.locator("#adv_keyword").fill("playwright")
page.get_by_text("时间不限").click()
page.get_by_text("一月内").click()
page.locator("input[name=\"q6\"]").click()
page.locator("input[name=\"q6\"]").fill("zhihu.com")
with page.expect_popup() as page1_info:
page.get_by_role("button", name="高级搜索").click()
page1 = page1_info.value
time.sleep(20)
page1.close()
page.close()
# ---------------------
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
# playwright codegen -o mytest_bd.py --target python -b chromium
案例代码2
通过命令生成获取天气脚本
import re
import time
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://www.weather.com.cn/")
page.locator("#txtZip").click()
page.locator("#txtZip").fill("虢镇")
with page.expect_popup() as page1_info:
page.get_by_text("虢镇街道-陈仓-陕西").click()
page1 = page1_info.value
page1.get_by_role("link", name="7天").click()
time.sleep(20)
page1.close()
page.close()
# ---------------------
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
# playwright codegen -o mytest_tq.py --target python -b chromium
☆☆☆案例3
写一个html通过playwright进行测试
html代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Playwright 功能演示页面</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #4361ee;
--secondary: #3f37c9;
--success: #4cc9f0;
--danger: #f72585;
--warning: #ffaa00;
--dark: #212529;
--light: #f8f9fa;
--gray: #6c757d;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
color: var(--dark);
line-height: 1.6;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
padding: 30px 0;
margin-bottom: 30px;
background: rgba(255, 255, 255, 0.9);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
h1 {
color: var(--primary);
font-size: 2.8rem;
margin-bottom: 10px;
}
.subtitle {
color: var(--gray);
font-size: 1.2rem;
max-width: 800px;
margin: 0 auto;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 25px;
margin-bottom: 40px;
}
.feature-card {
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.feature-card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
}
.card-header {
background: linear-gradient(to right, var(--primary), var(--secondary));
color: white;
padding: 20px;
display: flex;
align-items: center;
gap: 15px;
}
.card-header i {
font-size: 1.8rem;
}
.card-body {
padding: 25px;
}
.card-title {
font-size: 1.5rem;
margin-bottom: 15px;
color: var(--dark);
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--gray);
}
input, select, textarea {
width: 100%;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.3s;
}
input:focus, select:focus, textarea:focus {
border-color: var(--primary);
outline: none;
}
.btn {
display: inline-block;
padding: 12px 25px;
background: var(--primary);
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
}
.btn:hover {
background: var(--secondary);
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(67, 97, 238, 0.3);
}
.btn-danger {
background: var(--danger);
}
.btn-danger:hover {
background: #d1146a;
}
.btn-success {
background: var(--success);
}
.btn-success:hover {
background: #2fbde5;
}
.result-box {
margin-top: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid var(--primary);
min-height: 50px;
font-family: monospace;
}
.checkbox-group, .radio-group {
display: flex;
gap: 15px;
margin-top: 10px;
}
.checkbox-item, .radio-item {
display: flex;
align-items: center;
gap: 8px;
}
.drag-container {
display: flex;
gap: 20px;
margin: 20px 0;
}
.drag-source {
padding: 30px;
background: var(--primary);
color: white;
border-radius: 8px;
text-align: center;
cursor: grab;
}
.drag-target {
padding: 30px;
background: #e9ecef;
border: 2px dashed var(--gray);
border-radius: 8px;
text-align: center;
flex-grow: 1;
}
.hover-box {
padding: 25px;
background: var(--warning);
color: white;
border-radius: 8px;
text-align: center;
margin: 20px 0;
transition: all 0.3s ease;
}
.hover-box:hover {
background: #ff9900;
transform: scale(1.05);
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 15px;
max-width: 500px;
width: 90%;
position: relative;
}
.close-modal {
position: absolute;
top: 15px;
right: 15px;
font-size: 1.5rem;
cursor: pointer;
color: var(--gray);
}
.tabs {
display: flex;
border-bottom: 1px solid #dee2e6;
margin-bottom: 20px;
}
.tab {
padding: 12px 25px;
cursor: pointer;
background: #f8f9fa;
border: 1px solid transparent;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.tab.active {
background: white;
border-color: #dee2e6;
border-bottom-color: white;
font-weight: 500;
}
.tab-content {
display: none;
padding: 20px;
border: 1px solid #dee2e6;
border-top: none;
border-radius: 0 0 8px 8px;
}
.tab-content.active {
display: block;
}
footer {
text-align: center;
padding: 30px 0;
color: var(--gray);
font-size: 0.9rem;
}
.highlight {
background: rgba(67, 97, 238, 0.1);
padding: 3px 6px;
border-radius: 4px;
font-weight: 500;
}
@media (max-width: 768px) {
.features-grid {
grid-template-columns: 1fr;
}
.drag-container {
flex-direction: column;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-robot"></i> Playwright 功能演示页面</h1>
<p class="subtitle">此页面包含多种交互元素,用于演示 Playwright
的各种自动化功能,包括表单操作、元素定位、事件处理、文件上传等</p>
</header>
<div class="features-grid">
<!-- 表单操作 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-edit"></i>
<h2>表单操作</h2>
</div>
<div class="card-body">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" placeholder="输入用户名">
</div>
<div class="form-group">
<label for="email">电子邮箱</label>
<input type="email" id="email" placeholder="输入邮箱地址">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" placeholder="输入密码">
</div>
<div class="form-group">
<label for="bio">个人简介</label>
<textarea id="bio" rows="3" placeholder="输入个人简介"></textarea>
</div>
<div class="form-group">
<label for="country">国家</label>
<select id="country">
<option value="">选择国家</option>
<option value="us">美国</option>
<option value="cn">中国</option>
<option value="jp">日本</option>
<option value="uk">英国</option>
</select>
</div>
<button id="submit-form" class="btn">提交表单</button>
<div class="result-box" id="form-result"></div>
</div>
</div>
<!-- 选择框和按钮 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-check-square"></i>
<h2>选择框与按钮</h2>
</div>
<div class="card-body">
<div class="form-group">
<label>选择技术</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="playwright" value="playwright">
<label for="playwright">Playwright</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="selenium" value="selenium">
<label for="selenium">Selenium</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="cypress" value="cypress">
<label for="cypress">Cypress</label>
</div>
</div>
</div>
<div class="form-group">
<label>选择语言</label>
<div class="radio-group">
<div class="radio-item">
<input type="radio" id="python" name="language" value="python">
<label for="python">Python</label>
</div>
<div class="radio-item">
<input type="radio" id="javascript" name="language" value="javascript">
<label for="javascript">JavaScript</label>
</div>
<div class="radio-item">
<input type="radio" id="java" name="language" value="java">
<label for="java">Java</label>
</div>
</div>
</div>
<div class="form-group">
<label>按钮操作</label>
<div style="display: flex; gap: 15px; margin-top: 15px;">
<button id="alert-btn" class="btn btn-danger">触发警告框</button>
<button id="confirm-btn" class="btn btn-success">触发确认框</button>
</div>
</div>
<div class="result-box" id="selection-result"></div>
</div>
</div>
<!-- 拖放与悬停 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-hand-pointer"></i>
<h2>拖放与悬停</h2>
</div>
<div class="card-body">
<h3 class="card-title">拖放操作</h3>
<div class="drag-container">
<div class="drag-source" id="drag-source" draggable="true">
<i class="fas fa-grip-lines fa-2x"></i>
<p>拖拽我</p>
</div>
<div class="drag-target" id="drag-target">
<p>拖放到此处</p>
</div>
</div>
<h3 class="card-title" style="margin-top: 30px;">鼠标悬停</h3>
<div class="hover-box" id="hover-area">
<i class="fas fa-mouse-pointer fa-3x"></i>
<p>将鼠标悬停在此处</p>
<p id="hover-text">悬停状态: 未激活</p>
</div>
<div class="result-box" id="drag-result">拖放结果将显示在这里</div>
</div>
</div>
<!-- 文件上传与下载 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-file-upload"></i>
<h2>文件操作</h2>
</div>
<div class="card-body">
<div class="form-group">
<label for="file-upload">上传文件</label>
<input type="file" id="file-upload">
</div>
<div class="result-box" id="upload-result">选择文件后,文件名将显示在这里</div>
<div style="margin-top: 30px; padding: 20px; background: #e7f4ff; border-radius: 10px;">
<h3 class="card-title">下载示例</h3>
<p>点击下方按钮下载示例文件:</p>
<button id="download-btn" class="btn" style="margin-top: 15px;">
<i class="fas fa-download"></i> 下载示例文件
</button>
</div>
</div>
</div>
<!-- 模态框与导航 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-window-maximize"></i>
<h2>模态框与导航</h2>
</div>
<div class="card-body">
<button id="open-modal" class="btn" style="margin-bottom: 20px;">
<i class="fas fa-external-link-alt"></i> 打开模态框
</button>
<div class="tabs">
<div class="tab active" data-tab="tab1">标签页 1</div>
<div class="tab" data-tab="tab2">标签页 2</div>
<div class="tab" data-tab="tab3">标签页 3</div>
</div>
<div class="tab-content active" id="tab1">
<h3>标签页 1 内容</h3>
<p>这是第一个标签页的内容。Playwright 可以处理标签页的切换操作。</p>
</div>
<div class="tab-content" id="tab2">
<h3>标签页 2 内容</h3>
<p>这是第二个标签页的内容。通过 Playwright 可以轻松定位和操作标签页。</p>
</div>
<div class="tab-content" id="tab3">
<h3>标签页 3 内容</h3>
<p>这是第三个标签页的内容。自动化测试中标签页切换是常见场景。</p>
</div>
<div style="margin-top: 30px;">
<h3 class="card-title">导航链接</h3>
<div style="display: flex; gap: 15px; flex-wrap: wrap; margin-top: 15px;">
<a href="#" class="btn" id="external-link">外部链接</a>
<a href="#" class="btn" id="new-tab-link">新标签页打开</a>
</div>
</div>
</div>
</div>
<!-- 动态内容 -->
<div class="feature-card">
<div class="card-header">
<i class="fas fa-sync-alt"></i>
<h2>动态内容加载</h2>
</div>
<div class="card-body">
<button id="load-content" class="btn" style="margin-bottom: 20px;">
<i class="fas fa-redo"></i> 加载动态内容
</button>
<div class="result-box" id="dynamic-content">
点击按钮加载内容...
</div>
<div style="margin-top: 30px;">
<h3 class="card-title">AJAX 数据加载</h3>
<button id="load-data" class="btn">
<i class="fas fa-database"></i> 加载用户数据
</button>
<div id="user-data"
style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px;"></div>
</div>
</div>
</div>
</div>
</div>
<!-- 模态框 -->
<div class="modal" id="demo-modal">
<div class="modal-content">
<span class="close-modal" id="close-modal">×</span>
<h2>Playwright 模态框演示</h2>
<p>这是一个模态框示例。Playwright 可以处理模态框的打开和关闭操作。</p>
<p>尝试在模态框中操作元素:</p>
<div class="form-group" style="margin: 20px 0;">
<input type="text" id="modal-input" placeholder="在模态框中输入文本">
</div>
<button id="modal-action" class="btn">模态框操作</button>
</div>
</div>
<footer>
<p>设计用于 Playwright 自动化测试演示 | 包含表单、选择框、按钮、拖放、悬停、文件操作、模态框、导航等交互元素</p>
<p>使用 <span class="highlight">page.fill()</span>, <span class="highlight">page.click()</span>, <span
class="highlight">page.selectOption()</span>, <span class="highlight">page.dragAndDrop()</span> 等方法操作这些元素
</p>
</footer>
<script>
// 表单提交
document.getElementById('submit-form').addEventListener('click', function () {
const username = document.getElementById('username').value;
const email = document.getElementById('email').value;
const country = document.getElementById('country').value;
if (username && email && country) {
document.getElementById('form-result').textContent =
`表单提交成功! 用户名: ${username}, 邮箱: ${email}, 国家: ${country}`;
} else {
document.getElementById('form-result').textContent = '请填写所有必填字段!';
}
});
// 选择框状态显示
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const radios = document.querySelectorAll('input[type="radio"]');
function updateSelectionResult() {
const selectedTech = Array.from(checkboxes)
.filter(cb => cb.checked)
.map(cb => cb.nextElementSibling.textContent)
.join(', ');
const selectedLang = Array.from(radios)
.filter(radio => radio.checked)
.map(radio => radio.nextElementSibling.textContent)
.join(', ');
let result = '';
if (selectedTech) result += `选择的技术: ${selectedTech}\n`;
if (selectedLang) result += `选择的语言: ${selectedLang}`;
document.getElementById('selection-result').textContent = result || '未选择任何选项';
}
checkboxes.forEach(cb => cb.addEventListener('change', updateSelectionResult));
radios.forEach(radio => radio.addEventListener('change', updateSelectionResult));
// 按钮操作
document.getElementById('alert-btn').addEventListener('click', function () {
alert('这是一个警告对话框! Playwright 可以处理这类弹窗。');
});
document.getElementById('confirm-btn').addEventListener('click', function () {
const confirmed = confirm('这是一个确认对话框。你确定要继续吗?');
document.getElementById('selection-result').textContent =
confirmed ? '用户点击了确定' : '用户点击了取消';
});
// 拖放功能
const dragSource = document.getElementById('drag-source');
const dragTarget = document.getElementById('drag-target');
dragSource.addEventListener('dragstart', function (e) {
e.dataTransfer.setData('text/plain', '拖放内容');
});
dragTarget.addEventListener('dragover', function (e) {
e.preventDefault();
this.style.borderColor = '#4361ee';
this.style.backgroundColor = '#d7e3fc';
});
dragTarget.addEventListener('dragleave', function () {
this.style.borderColor = '#6c757d';
this.style.backgroundColor = '';
});
dragTarget.addEventListener('drop', function (e) {
e.preventDefault();
const data = e.dataTransfer.getData('text/plain');
this.innerHTML = `<p>拖放成功! 内容: "${data}"</p>`;
this.style.borderColor = '#28a745';
this.style.backgroundColor = '#d4edda';
document.getElementById('drag-result').textContent = '拖放操作完成!';
});
// 鼠标悬停
const hoverArea = document.getElementById('hover-area');
const hoverText = document.getElementById('hover-text');
hoverArea.addEventListener('mouseenter', function () {
hoverText.textContent = '悬停状态: 激活';
this.style.backgroundColor = '#ff9900';
});
hoverArea.addEventListener('mouseleave', function () {
hoverText.textContent = '悬停状态: 未激活';
this.style.backgroundColor = '#ffaa00';
});
// 文件上传
document.getElementById('file-upload').addEventListener('change', function (e) {
if (this.files.length > 0) {
document.getElementById('upload-result').textContent =
`已选择文件: ${this.files[0].name}`;
} else {
document.getElementById('upload-result').textContent = '未选择文件';
}
});
// 下载按钮
document.getElementById('download-btn').addEventListener('click', function () {
alert('在真实场景中,这将触发文件下载。Playwright 可以处理文件下载操作。');
});
// 模态框
const modal = document.getElementById('demo-modal');
const openModalBtn = document.getElementById('open-modal');
const closeModalBtn = document.getElementById('close-modal');
openModalBtn.addEventListener('click', function () {
modal.style.display = 'flex';
});
closeModalBtn.addEventListener('click', function () {
modal.style.display = 'none';
});
window.addEventListener('click', function (e) {
if (e.target === modal) {
modal.style.display = 'none';
}
});
// 标签页
const tabs = document.querySelectorAll('.tab');
tabs.forEach(tab => {
tab.addEventListener('click', function () {
// 移除所有active类
tabs.forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(tc => tc.classList.remove('active'));
// 添加active类到当前标签
this.classList.add('active');
const tabId = this.getAttribute('data-tab');
document.getElementById(tabId).classList.add('active');
});
});
// 动态内容加载
document.getElementById('load-content').addEventListener('click', function () {
const dynamicContent = document.getElementById('dynamic-content');
dynamicContent.innerHTML = `
<p>动态加载的内容 (${new Date().toLocaleTimeString()})</p>
<p>Playwright 可以等待动态内容加载完成后再进行操作。</p>
<ul>
<li>项目 1</li>
<li>项目 2</li>
<li>项目 3</li>
</ul>
`;
});
// 加载用户数据
document.getElementById('load-data').addEventListener('click', function () {
const userDataDiv = document.getElementById('user-data');
userDataDiv.innerHTML = '<p>加载中...</p>';
// 模拟 AJAX 请求延迟
setTimeout(() => {
userDataDiv.innerHTML = `
<h4>用户数据</h4>
<table style="width: 100%; border-collapse: collapse;">
<tr style="background-color: #f1f1f1;">
<th style="padding: 8px; text-align: left;">ID</th>
<th style="padding: 8px; text-align: left;">姓名</th>
<th style="padding: 8px; text-align: left;">邮箱</th>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">1</td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">张三</td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">zhangsan@example.com</td>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">2</td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">李四</td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">lisi@example.com</td>
</tr>
<tr>
<td style="padding: 8px;">3</td>
<td style="padding: 8px;">王五</td>
<td style="padding: 8px;">wangwu@example.com</td>
</tr>
</table>
`;
}, 1500);
});
// 初始化
updateSelectionResult();
</script>
</body>
</html>
Python代码
import time
from playwright.sync_api import sync_playwright
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.new_context(viewport={'width': 1920, 'height': 1080})
page = context.new_page()
page.goto("file:///D:/Project/2025/py-ml/005playwright_extend/index.html")
# 1. 表单操作
page.fill("#username", "testuser")
page.fill("#email", "test@example.com")
page.fill("#password", "securepassword123")
page.select_option("#country", "cn")
page.click("#submit-form")
time.sleep(2)
# 2. 选择框操作
page.check("#playwright")
page.check("#selenium")
page.click("#python")
time.sleep(2)
# 3. 按钮操作
page.on("dialog", lambda dialog: dialog.accept())
page.click("#alert-btn")
page.click("#confirm-btn")
time.sleep(2)
# 4. 拖放操作
page.drag_and_drop("#drag-source", "#drag-target")
time.sleep(2)
# 5. 文件上传
page.set_input_files("#file-upload", "testfile.txt")
time.sleep(2)
# 6. 模态框操作
page.click("#open-modal")
page.fill("#modal-input", "Playwright test")
page.click("#close-modal")
time.sleep(2)
# 7. 标签页操作
page.click("text=标签页 2")
time.sleep(2)
# 8. 动态内容加载
page.click("#load-content")
page.click("#load-data")
page.wait_for_selector("#user-data table")
time.sleep(2)
# 截图保存 类名 container
el = page.locator("div.container")
el.screenshot(path="playwright_demo_result.png")
# 获取页面html保存到save.html中
with open("save.html", "w", encoding="utf-8") as f:
f.write(page.content())
time.sleep(20)
browser.close()
with sync_playwright() as playwright:
run(playwright)

案例4自己本地项目,登录进去进入指定页面点击导出保存文件
from playwright.sync_api import sync_playwright
import os
def run():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
# 创建浏览器上下文并启用下载
download_path = os.path.abspath("my_downloads") # 设定你的下载目录
os.makedirs(download_path, exist_ok=True) # 确保目录存在
context = browser.new_context(accept_downloads=True)
page = context.new_page()
page.goto("http://192.168.90.36:90/")
page.screenshot(path="r_1.png")
# 等待登录框可见,填写登录信息
page.locator('div.loginBox').wait_for(state='visible')
page.fill('input.input-text.size-L.username', 'admin')
page.fill('input.input-text.size-L.password', '123456')
page.screenshot(path="r_2.png")
# 点击登录按钮
page.locator('input.btn.btn-success.radius.size-L.login').click()
# 等待 iframe 加载完成
page.locator('div#iframe_box').wait_for(state='visible')
page.screenshot(path="r_3.png")
# 跳转到目标页面
page.goto("http://192.168.90.36:90/yhq_exception/yhq27")
# 等待导出按钮加载完成
page.locator('button.btn.btn-primary.size-MINI').filter(has_text='导出').wait_for(state='visible')
page.screenshot(path="r_4.png")
# 使用 expect_download 监听下载
with page.expect_download() as download_info:
page.locator('button.btn.btn-primary.size-MINI').filter(has_text='导出').click()
# 获取下载的文件
download = download_info.value
download_path = os.path.join('my_downloads', download.suggested_filename)
# 将文件保存到指定的路径
download.save_as(download_path)
print(f"Downloaded file saved at: {download_path}")
# 等待文件下载完成
# page.wait_for_timeout(60000)
browser.close()
if __name__ == '__main__':
run()
更多推荐
所有评论(0)