本文通过一个完整示例,演示如何使用 Puppeteer 自动访问后台系统、设置 Cookie、切换分页大小,并循环点击「下一页」抓取所有表格 HTML 数据。
一、应用场景说明
在实际项目中,我们经常遇到以下需求:
- 后台系统需要登录才能访问
- 数据列表有分页,需要自动翻页
- 希望批量抓取每一页的表格数据
- 页面基于 Element UI(
el-pager、btn-next)
本文将一步步实现:
✅ 打开后台页面
✅ 使用 Cookie 模拟登录
✅ 切换为 50 条/页
✅ 自动计算总页数
✅ 循环点击「下一页」
✅ 抓取所有表格 HTML
二、环境准备
1. 安装 Puppeteer
bash
npm install puppeteer
2. Node.js 版本
建议使用:
- Node.js ≥ 14
- Puppeteer ≥ 19
三、完整示例代码
下面是完整可运行的示例代码:
js
const puppeteer = require('puppeteer');
const fs = require('fs');
// 封装一个延时方法
function waitForTimeout(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
(async () => {
const browser = await puppeteer.launch({
headless: false // 关闭无头模式,方便调试
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 800 });
// 1. 进入后台登录页面
await page.goto('http://localhost:8093/admin');
// 2. 设置登录 Cookie(模拟已登录)
const cookies = [
{
name: 'Admin-Token',
value: '你的 token',
domain: 'localhost',
path: '/'
}
];
// 如果需要启用 Cookie,取消注释
// await page.setCookie(...cookies);
// 3. 跳转到数据列表页
await page.goto('http://localhost:8093/category');
// 4. 切换分页大小为 50 条/页
const pageSizeXPath = '//span[text()="50条/页"]';
await page.waitForXPath(pageSizeXPath);
const [pageSizeBtn] = await page.$x(pageSizeXPath);
if (pageSizeBtn) {
await pageSizeBtn.evaluate(el => el.click());
console.log('已切换为 50 条/页');
}
// 5. 获取总页数
await page.waitForSelector('ul.el-pager');
const liElements = await page.$$('ul.el-pager li');
const lastLi = liElements[liElements.length - 1];
let totalPages = 1;
if (lastLi) {
totalPages = parseInt(
await page.evaluate(li => li.textContent, lastLi)
);
console.log('总页数:', totalPages);
}
// 6. 循环点击下一页并抓取表格
const tableSelector = 'table';
const nextBtnSelector = 'button.btn-next';
await page.waitForSelector(nextBtnSelector, { visible: true });
let currentPage = 1;
let allTableHTML = '';
while (currentPage <= totalPages) {
console.log(`正在抓取第 ${currentPage} 页`);
// 抓取当前页表格
const tables = await page.$$(tableSelector);
for (const table of tables) {
const html = await table.evaluate(el => el.outerHTML);
allTableHTML += html + '\n\n';
}
// 点击下一页
const nextBtn = await page.$(nextBtnSelector);
if (!nextBtn) break;
await nextBtn.click();
await waitForTimeout(3000);
currentPage++;
}
console.log('分页抓取完成');
// 7. 可选:保存为 HTML 文件
fs.writeFileSync('tables.html', allTableHTML, 'utf-8');
console.log('表格 HTML 已保存到 tables.html');
// await browser.close();
} catch (e) {
console.error('发生错误:', e);
}
})();
四、关键代码讲解
1️⃣ 模拟登录(Cookie)
js
await page.setCookie({
name: 'Admin-Token',
value: 'xxx',
domain: 'localhost',
path: '/'
});
适用于:
- 后台 token 登录
- 无需输入账号密码
- 常见于 Vue / Element UI 项目
2️⃣ XPath 精准点击「50条/页」
js
const xpath = '//span[text()="50条/页"]';
const [el] = await page.$x(xpath);
await el.evaluate(e => e.click());
优点:
- 不依赖 class
- 文本唯一即可定位
3️⃣ 获取 Element UI 总页数
js
ul.el-pager li:last-child
Element UI 的分页结构非常规整,最后一个 li 就是最大页数。
4️⃣ 自动翻页核心逻辑
js
while (currentPage <= totalPages) {
await nextBtn.click();
await waitForTimeout(3000);
}
建议:
- 使用显式等待
- 避免点击过快导致请求丢失