Puppeteer 用户交互 #
点击操作 #
基本点击 #
javascript
// 点击元素
await page.click('#button');
// 点击选择器
await page.click('.submit-button');
// 点击 XPath 元素
const [button] = await page.$x('//button[contains(text(), "提交")]');
await button.click();
点击选项 #
javascript
await page.click('#button', {
button: 'left', // 鼠标按钮: left, right, middle
clickCount: 1, // 点击次数: 1 单击, 2 双击
delay: 100 // 点击延迟(毫秒)
});
// 双击
await page.click('#element', { clickCount: 2 });
// 右键点击
await page.click('#element', { button: 'right' });
等待后点击 #
javascript
// 等待元素可见后点击
await page.waitForSelector('#button', { visible: true });
await page.click('#button');
// 使用 Locator API(推荐)
await page.locator('#button').click();
点击隐藏元素 #
javascript
// 强制点击(忽略可见性检查)
await page.click('#hidden-button', { force: true });
// 使用 evaluate 触发点击
await page.evaluate(() => {
document.querySelector('#hidden-button').click();
});
输入操作 #
文本输入 #
javascript
// 基本输入
await page.type('#username', 'john_doe');
// 带延迟输入(模拟真实打字)
await page.type('#username', 'john_doe', { delay: 100 });
// 清空后输入
await page.locator('#username').fill('new_value');
// 直接设置值(不触发事件)
await page.$eval('#username', el => el.value = 'direct_value');
输入方法对比 #
text
┌─────────────────────────────────────────────────────────────┐
│ 输入方法对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ page.type() 逐字符输入,触发 keydown/keyup/keypress │
│ 适合需要触发输入事件的场景 │
│ │
│ locator.fill() 直接设置值,触发 input/change 事件 │
│ 推荐用于表单填充 │
│ │
│ $eval() 直接设置 value 属性 │
│ 不触发任何事件 │
│ │
└─────────────────────────────────────────────────────────────┘
密码输入 #
javascript
// 输入密码
await page.type('#password', 'mySecretPassword', { delay: 50 });
// 使用 fill
await page.locator('#password').fill('mySecretPassword');
清除输入 #
javascript
// 方法一:使用 fill
await page.locator('#input').fill('');
// 方法二:使用键盘
await page.click('#input');
await page.keyboard.down('Control');
await page.keyboard.press('a');
await page.keyboard.up('Control');
await page.keyboard.press('Backspace');
// 方法三:使用 evaluate
await page.$eval('#input', el => el.value = '');
键盘操作 #
键盘按键 #
javascript
// 按下单个键
await page.keyboard.press('Enter');
await page.keyboard.press('Tab');
await page.keyboard.press('Escape');
// 按下并释放
await page.keyboard.down('Shift');
await page.keyboard.press('KeyA');
await page.keyboard.up('Shift');
// 组合键
await page.keyboard.down('Control');
await page.keyboard.press('a');
await page.keyboard.up('Control');
常用按键 #
javascript
// 功能键
await page.keyboard.press('Enter');
await page.keyboard.press('Tab');
await page.keyboard.press('Escape');
await page.keyboard.press('Backspace');
await page.keyboard.press('Delete');
await page.keyboard.press('Space');
// 方向键
await page.keyboard.press('ArrowUp');
await page.keyboard.press('ArrowDown');
await page.keyboard.press('ArrowLeft');
await page.keyboard.press('ArrowRight');
// 修饰键
await page.keyboard.press('Control');
await page.keyboard.press('Alt');
await page.keyboard.press('Shift');
await page.keyboard.press('Meta'); // Command (Mac) / Windows (Win)
快捷键组合 #
javascript
// Ctrl+A 全选
await page.keyboard.down('Control');
await page.keyboard.press('a');
await page.keyboard.up('Control');
// Ctrl+C 复制
await page.keyboard.down('Control');
await page.keyboard.press('c');
await page.keyboard.up('Control');
// Ctrl+V 粘贴
await page.keyboard.down('Control');
await page.keyboard.press('v');
await page.keyboard.up('Control');
// Ctrl+Enter 提交
await page.keyboard.down('Control');
await page.keyboard.press('Enter');
await page.keyboard.up('Control');
输入文本 #
javascript
// 直接输入文本
await page.keyboard.type('Hello World');
// 带延迟输入
await page.keyboard.type('Hello World', { delay: 100 });
发送字符 #
javascript
// 发送单个字符
await page.keyboard.sendCharacter('嗨');
// 区别:sendCharacter 触发 keypress,不触发 keydown/keyup
鼠标操作 #
鼠标移动 #
javascript
// 移动到指定位置
await page.mouse.move(100, 200);
// 带步数的移动(模拟真实轨迹)
await page.mouse.move(100, 200, { steps: 10 });
// 移动到元素
const element = await page.$('.target');
const box = await element.boundingBox();
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
鼠标点击 #
javascript
// 单击
await page.mouse.click(100, 200);
// 双击
await page.mouse.click(100, 200, { clickCount: 2 });
// 右键点击
await page.mouse.click(100, 200, { button: 'right' });
// 带延迟点击
await page.mouse.click(100, 200, { delay: 100 });
鼠标按下和释放 #
javascript
// 按下
await page.mouse.down();
// 移动(拖拽)
await page.mouse.move(200, 300);
// 释放
await page.mouse.up();
拖拽操作 #
javascript
// 拖拽元素
const source = await page.$('.draggable');
const target = await page.$('.drop-zone');
const sourceBox = await source.boundingBox();
const targetBox = await target.boundingBox();
// 移动到源元素
await page.mouse.move(
sourceBox.x + sourceBox.width / 2,
sourceBox.y + sourceBox.height / 2
);
// 按下
await page.mouse.down();
// 移动到目标位置
await page.mouse.move(
targetBox.x + targetBox.width / 2,
targetBox.y + targetBox.height / 2,
{ steps: 20 } // 分步移动,更真实
);
// 释放
await page.mouse.up();
滚动操作 #
javascript
// 使用 wheel 滚动
await page.mouse.wheel({ deltaY: 300 });
// 水平滚动
await page.mouse.wheel({ deltaX: 300 });
// 滚动到元素
await page.$eval('.target', element => {
element.scrollIntoView({ behavior: 'smooth' });
});
// 滚动到页面底部
await page.evaluate(() => {
window.scrollTo(0, document.body.scrollHeight);
});
选择操作 #
下拉选择 #
javascript
// 选择选项(按 value)
await page.select('#country', 'us');
// 选择选项(按文本)
await page.select('#country', 'United States');
// 多选
await page.select('#languages', 'en', 'zh', 'ja');
// 获取选中值
const selectedValue = await page.$eval('#country', el => el.value);
复选框操作 #
javascript
// 勾选复选框
await page.check('#agree');
// 取消勾选
await page.uncheck('#agree');
// 检查是否选中
const isChecked = await page.$eval('#agree', el => el.checked);
// 点击切换
await page.click('#checkbox');
单选框操作 #
javascript
// 选择单选项
await page.click('input[type="radio"][value="option1"]');
// 使用 check
await page.check('input[type="radio"][value="option1"]');
// 检查是否选中
const isSelected = await page.$eval(
'input[type="radio"][value="option1"]',
el => el.checked
);
文件上传 #
基本文件上传 #
javascript
// 方式一:使用 inputFile
const fileInput = await page.$('input[type="file"]');
await fileInput.uploadFile('./path/to/file.pdf');
// 方式二:使用 locator
await page.locator('input[type="file"]').setInputFiles('./path/to/file.pdf');
多文件上传 #
javascript
// 上传多个文件
await page.locator('input[type="file"]').setInputFiles([
'./file1.pdf',
'./file2.pdf',
'./file3.pdf'
]);
使用 Buffer 上传 #
javascript
const fs = require('fs');
// 从 Buffer 上传
const buffer = fs.readFileSync('./file.pdf');
await page.locator('input[type="file"]').setInputFiles({
name: 'file.pdf',
mimeType: 'application/pdf',
buffer: buffer
});
拖拽上传 #
javascript
const fs = require('fs');
// 获取上传区域
const dropZone = await page.$('.drop-zone');
const box = await dropZone.boundingBox();
// 创建文件数据
const fileContent = fs.readFileSync('./file.pdf');
// 模拟拖拽上传
await page.evaluate((data) => {
const dropZone = document.querySelector('.drop-zone');
const file = new File([data.content], data.name, { type: data.type });
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
const dropEvent = new DropEvent('drop', {
dataTransfer: dataTransfer
});
dropZone.dispatchEvent(dropEvent);
}, {
content: fileContent,
name: 'file.pdf',
type: 'application/pdf'
});
高级交互 #
悬停操作 #
javascript
// 悬停在元素上
await page.hover('.menu-item');
// 等待下拉菜单出现
await page.waitForSelector('.dropdown-menu', { visible: true });
// 点击下拉菜单项
await page.click('.dropdown-menu .item');
焦点操作 #
javascript
// 聚焦元素
await page.focus('#input');
// 获取当前焦点元素
const focusedElement = await page.evaluateHandle(
() => document.activeElement
);
滚动到元素 #
javascript
// 滚动到元素可见
await page.$eval('.target', el => {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
});
// 使用 Locator API
await page.locator('.target').scrollIntoViewIfNeeded();
拖放操作 #
javascript
// 使用 HTML5 拖放 API
await page.evaluate(() => {
const source = document.querySelector('.draggable');
const target = document.querySelector('.drop-zone');
const dataTransfer = new DataTransfer();
source.dispatchEvent(new DragEvent('dragstart', { dataTransfer }));
target.dispatchEvent(new DragEvent('dragover', { dataTransfer }));
target.dispatchEvent(new DragEvent('drop', { dataTransfer }));
source.dispatchEvent(new DragEvent('dragend', { dataTransfer }));
});
触摸操作 #
javascript
// 点击触摸
await page.tap('#button');
// 触摸滑动
await page.touchscreen.tap(100, 200);
// 模拟触摸事件
await page.evaluate(() => {
const element = document.querySelector('.target');
const touch = new Touch({
identifier: 0,
target: element,
clientX: 100,
clientY: 200
});
element.dispatchEvent(new TouchEvent('touchstart', {
touches: [touch],
bubbles: true
}));
});
等待与同步 #
等待元素可交互 #
javascript
// 等待元素可见
await page.waitForSelector('#button', { visible: true });
// 等待元素可点击
await page.waitForSelector('#button', { visible: true, enabled: true });
// 使用 Locator API(自动等待)
await page.locator('#button').click();
等待动画完成 #
javascript
// 等待动画结束
await page.waitForFunction(
selector => {
const element = document.querySelector(selector);
return element && window.getComputedStyle(element).animationPlayState === 'paused';
},
{},
'.animated-element'
);
等待元素稳定 #
javascript
// 等待元素不再移动
let lastPosition;
let stableCount = 0;
while (stableCount < 3) {
const box = await page.$eval('.element', el => {
const rect = el.getBoundingClientRect();
return { x: rect.x, y: rect.y };
});
if (lastPosition && box.x === lastPosition.x && box.y === lastPosition.y) {
stableCount++;
} else {
stableCount = 0;
}
lastPosition = box;
await page.waitForTimeout(100);
}
完整示例 #
登录流程自动化 #
javascript
const puppeteer = require('puppeteer');
async function login(url, credentials) {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
try {
// 访问登录页
await page.goto(url);
// 等待登录表单加载
await page.waitForSelector('#login-form');
// 填写用户名
await page.locator('#username').fill(credentials.username);
// 填写密码
await page.locator('#password').fill(credentials.password);
// 勾选记住我
await page.check('#remember-me');
// 点击登录
await page.click('#login-button');
// 等待导航完成
await page.waitForNavigation({ waitUntil: 'networkidle0' });
// 验证登录成功
const welcomeText = await page.$eval('.welcome', el => el.textContent);
console.log('Login successful:', welcomeText);
return true;
} catch (error) {
console.error('Login failed:', error);
return false;
} finally {
await browser.close();
}
}
login('https://example.com/login', {
username: 'testuser',
password: 'password123'
});
表单填写示例 #
javascript
const puppeteer = require('puppeteer');
async function fillForm(url, formData) {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(url);
// 填写文本字段
await page.locator('#name').fill(formData.name);
await page.locator('#email').fill(formData.email);
await page.locator('#phone').fill(formData.phone);
// 选择下拉框
await page.select('#country', formData.country);
// 选择日期
await page.locator('#birthdate').fill(formData.birthdate);
// 选择性别
await page.check(`input[name="gender"][value="${formData.gender}"]`);
// 勾选复选框
for (const interest of formData.interests) {
await page.check(`input[name="interests"][value="${interest}"]`);
}
// 上传头像
await page.locator('input[type="file"][name="avatar"]').setInputFiles(formData.avatar);
// 填写文本区域
await page.locator('#bio').fill(formData.bio);
// 提交表单
await page.click('#submit');
// 等待成功消息
await page.waitForSelector('.success-message');
await browser.close();
}
fillForm('https://example.com/register', {
name: 'John Doe',
email: 'john@example.com',
phone: '1234567890',
country: 'US',
birthdate: '1990-01-01',
gender: 'male',
interests: ['coding', 'music'],
avatar: './avatar.jpg',
bio: 'Hello, I am John!'
});
拖拽排序示例 #
javascript
const puppeteer = require('puppeteer');
async function dragAndDropSort(url) {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(url);
// 获取所有可拖拽项
const items = await page.$$('.sortable-item');
// 将第一项拖到最后一项后面
const firstItem = items[0];
const lastItem = items[items.length - 1];
const firstBox = await firstItem.boundingBox();
const lastBox = await lastItem.boundingBox();
// 移动到第一项
await page.mouse.move(
firstBox.x + firstBox.width / 2,
firstBox.y + firstBox.height / 2
);
// 按下
await page.mouse.down();
// 移动到最后一项下方
await page.mouse.move(
lastBox.x + lastBox.width / 2,
lastBox.y + lastBox.height + 10,
{ steps: 20 }
);
// 释放
await page.mouse.up();
await browser.close();
}
下一步 #
现在你已经掌握了 Puppeteer 的用户交互操作,接下来学习 JavaScript 执行与页面评估 了解如何在页面中执行 JavaScript!
最后更新:2026-03-28