本章概述

本章将介绍Puppeteer的基础概念、发展历史、核心特性,并详细讲解如何搭建Puppeteer开发环境。通过本章学习,您将了解Puppeteer的工作原理,掌握环境配置方法,并能够运行第一个Puppeteer程序。

学习目标

- 理解Puppeteer的基本概念和工作原理 - 掌握Puppeteer的核心特性和应用场景 - 学会搭建Puppeteer开发环境 - 能够编写和运行基础的Puppeteer脚本 - 了解Puppeteer的配置选项和最佳实践

1.1 Puppeteer简介

1.1.1 什么是Puppeteer

Puppeteer是由Google Chrome团队开发的一个Node.js库,它提供了一套高级API来控制Chrome或Chromium浏览器。Puppeteer可以通过DevTools协议与浏览器进行通信,实现自动化操作。 javascript // Puppeteer的基本工作流程 const puppeteer = require('puppeteer'); (async () => { // 1. 启动浏览器实例 const browser = await puppeteer.launch(); // 2. 创建新页面 const page = await browser.newPage(); // 3. 导航到目标网页 await page.goto('https://example.com'); // 4. 执行操作(截图、点击、输入等) await page.screenshot({ path: 'example.png' }); // 5. 关闭浏览器 await browser.close(); })();

1.1.2 Puppeteer的发展历史

- 2017年8月:Google发布Puppeteer 0.9.0版本 - 2018年1月:发布1.0.0稳定版本 - 2019年5月:支持Firefox浏览器(实验性) - 2020年1月:发布2.0.0版本,改进API设计 - 2021年8月:发布10.0.0版本,支持新的Chrome特性 - 2022年2月:发布13.0.0版本,改进TypeScript支持 - 2023年5月:发布20.0.0版本,支持Chrome 113+ - 2024年1月:发布21.0.0版本,性能优化和新特性

1.1.3 核心概念

Browser(浏览器实例)

javascript // 启动浏览器实例 const browser = await puppeteer.launch({ headless: false, // 是否无头模式 devtools: true, // 是否打开开发者工具 slowMo: 100, // 操作延迟(毫秒) args: ['--no-sandbox', '--disable-setuid-sandbox'] }); // 获取浏览器信息 console.log('浏览器版本:', await browser.version()); console.log('用户代理:', await browser.userAgent());

Page(页面对象)

javascript // 创建新页面 const page = await browser.newPage(); // 设置页面属性 await page.setViewport({ width: 1920, height: 1080 }); await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); // 页面导航 await page.goto('https://example.com', { waitUntil: 'networkidle2', // 等待网络空闲 timeout: 30000 // 超时时间 });

ElementHandle(元素句柄)

javascript // 获取元素句柄 const element = await page.$('#submit-button'); const elements = await page.$$('.item'); // 操作元素 if (element) { await element.click(); await element.type('Hello World'); const text = await element.evaluate(el => el.textContent); }

1.2 Puppeteer的特性与优势

1.2.1 核心特性

🚀 完整的浏览器控制

javascript // 浏览器控制示例 const browser = await puppeteer.launch({ headless: false, defaultViewport: null, args: [ '--start-maximized', '--disable-web-security', '--disable-features=VizDisplayCompositor' ] }); // 多页面管理 const pages = await browser.pages(); const newPage = await browser.newPage(); await newPage.goto('https://google.com');

🎯 丰富的页面交互

javascript // 页面交互示例 const page = await browser.newPage(); await page.goto('https://example.com'); // 点击操作 await page.click('button[type="submit"]'); // 输入操作 await page.type('#username', 'testuser'); await page.type('#password', 'password123'); // 键盘操作 await page.keyboard.press('Enter'); await page.keyboard.down('Shift'); await page.keyboard.press('Tab'); await page.keyboard.up('Shift'); // 鼠标操作 await page.mouse.click(100, 100); await page.mouse.move(200, 200);

📊 强大的数据提取

javascript // 数据提取示例 const data = await page.evaluate(() => { // 在浏览器上下文中执行 const title = document.title; const links = Array.from(document.querySelectorAll('a')).map(a => ({ text: a.textContent, href: a.href })); return { title, links }; }); console.log('页面数据:', data);

🔍 网络监控

javascript // 网络请求监控 page.on('request', request => { console.log('请求:', request.url()); }); page.on('response', response => { console.log('响应:', response.url(), response.status()); }); // 请求拦截 await page.setRequestInterception(true); page.on('request', request => { if (request.resourceType() === 'image') { request.abort(); } else { request.continue(); } });

1.2.2 应用场景

自动化测试

javascript // E2E测试示例 const testLogin = async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); try { await page.goto('https://example.com/login'); // 填写登录表单 await page.type('#username', 'testuser'); await page.type('#password', 'password123'); await page.click('#login-button'); // 等待登录成功 await page.waitForSelector('.dashboard', { timeout: 5000 }); console.log('登录测试通过'); } catch (error) { console.error('登录测试失败:', error); } finally { await browser.close(); } };

网页爬虫

javascript // 爬虫示例 const scrapeNews = async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://news.example.com'); const articles = await page.evaluate(() => { return Array.from(document.querySelectorAll('.article')).map(article => ({ title: article.querySelector('.title')?.textContent, summary: article.querySelector('.summary')?.textContent, link: article.querySelector('a')?.href, publishTime: article.querySelector('.time')?.textContent })); }); await browser.close(); return articles; };

性能监控

javascript // 性能监控示例 const measurePerformance = async (url) => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // 开始性能追踪 await page.tracing.start({ path: 'trace.json' }); const startTime = Date.now(); await page.goto(url, { waitUntil: 'networkidle2' }); const loadTime = Date.now() - startTime; // 获取性能指标 const metrics = await page.metrics(); await page.tracing.stop(); await browser.close(); return { loadTime, metrics }; };

1.3 环境搭建

1.3.1 系统要求

操作系统支持

  • Windows: Windows 10 或更高版本

  • macOS: macOS 10.14 (Mojave) 或更高版本

  • Linux: Ubuntu 18.04, CentOS 7, 或其他现代Linux发行版

    硬件要求

  • CPU: 双核处理器或更高

  • 内存: 最少4GB RAM(推荐8GB或更高)

  • 存储: 至少2GB可用空间

  • 网络: 稳定的互联网连接

    1.3.2 Node.js安装

    Windows安装

    ”`powershell

    使用Chocolatey安装

    choco install nodejs

    或者使用Scoop安装

    scoop install nodejs

    验证安装

    node –version npm –version “`

    macOS安装

    ”`bash

    使用Homebrew安装

    brew install node

    或者使用MacPorts安装

    sudo port install nodejs18

    验证安装

    node –version npm –version “`

    Linux安装

    ”`bash

    Ubuntu/Debian

    curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs

    CentOS/RHEL

    curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash - sudo yum install -y nodejs

    验证安装

    node –version npm –version “`

    1.3.3 项目初始化

    创建项目目录

    ”`bash

    创建项目目录

    mkdir puppeteer-tutorial cd puppeteer-tutorial

    初始化npm项目

    npm init -y

    创建基本目录结构

    mkdir src tests examples touch src/index.js tests/test.js examples/basic.js “`

    package.json配置

    json { "name": "puppeteer-tutorial", "version": "1.0.0", "description": "Puppeteer自动化测试教程", "main": "src/index.js", "scripts": { "start": "node src/index.js", "test": "jest", "dev": "nodemon src/index.js", "example:basic": "node examples/basic.js", "example:screenshot": "node examples/screenshot.js" }, "keywords": ["puppeteer", "automation", "testing", "scraping"], "author": "Your Name", "license": "MIT", "dependencies": { "puppeteer": "^21.0.0" }, "devDependencies": { "@types/puppeteer": "^7.0.4", "jest": "^29.0.0", "nodemon": "^3.0.0", "typescript": "^5.0.0" } }

    1.3.4 Puppeteer安装

    标准安装

    ”`bash

    安装Puppeteer(包含Chromium)

    npm install puppeteer

    或者使用yarn

    yarn add puppeteer “`

    核心包安装

    ”`bash

    只安装核心包(不包含Chromium)

    npm install puppeteer-core

    需要单独指定浏览器路径

    const browser = await puppeteer.launch({ executablePath: ‘/path/to/chrome’ }); “`

    TypeScript支持

    ”`bash

    安装TypeScript类型定义

    npm install –save-dev @types/puppeteer typescript

    创建tsconfig.json

    npx tsc –init json // tsconfig.json { “compilerOptions”: { “target”: “ES2020”, “module”: “commonjs”, “lib”: [“ES2020”, “DOM”], “outDir”: “./dist”, “rootDir”: “./src”, “strict”: true, “esModuleInterop”: true, “skipLibCheck”: true, “forceConsistentCasingInFileNames”: true, “resolveJsonModule”: true }, “include”: [“src/*/”], “exclude”: [“node_modules”, “dist”] } “`

    1.3.5 环境验证

    基础验证脚本

    javascript // examples/basic.js const puppeteer = require('puppeteer'); (async () => { console.log('开始Puppeteer环境验证...'); try { // 启动浏览器 const browser = await puppeteer.launch({ headless: false, devtools: true }); console.log('✅ 浏览器启动成功'); console.log('浏览器版本:', await browser.version()); // 创建页面 const page = await browser.newPage(); console.log('✅ 页面创建成功'); // 导航到测试页面 await page.goto('https://example.com'); console.log('✅ 页面导航成功'); // 获取页面标题 const title = await page.title(); console.log('页面标题:', title); // 截图 await page.screenshot({ path: 'verification.png' }); console.log('✅ 截图保存成功: verification.png'); // 关闭浏览器 await browser.close(); console.log('✅ 环境验证完成'); } catch (error) { console.error('❌ 环境验证失败:', error); process.exit(1); } })();

    运行验证

    ”`bash

    运行验证脚本

    node examples/basic.js

    检查生成的截图

    ls -la verification.png “`

    1.4 配置选项详解

    1.4.1 浏览器启动选项

    javascript const browser = await puppeteer.launch({ // 基础选项 headless: false, // 是否无头模式 devtools: true, // 是否打开开发者工具 slowMo: 100, // 操作延迟(毫秒) // 浏览器路径 executablePath: '/path/to/chrome', // 自定义浏览器路径 // 窗口设置 defaultViewport: { width: 1920, height: 1080, deviceScaleFactor: 1, isMobile: false, hasTouch: false, isLandscape: false }, // 启动参数 args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--no-first-run', '--no-zygote', '--single-process', '--disable-gpu' ], // 超时设置 timeout: 30000, // 启动超时 // 忽略HTTPS错误 ignoreHTTPSErrors: true, // 用户数据目录 userDataDir: './user-data' });

    1.4.2 页面配置选项

    javascript const page = await browser.newPage(); // 设置视口 await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 1, isMobile: false, hasTouch: false, isLandscape: false }); // 设置用户代理 await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); // 设置额外HTTP头 await page.setExtraHTTPHeaders({ 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8' }); // 设置地理位置 await page.setGeolocation({ latitude: 39.9042, longitude: 116.4074 }); // 设置时区 await page.emulateTimezone('Asia/Shanghai'); // 设置媒体类型 await page.emulateMediaType('screen'); // 设置CPU限制 await page.setCPUThrottlingRate(4);

    1.4.3 环境变量配置

    “`bash

    .env文件

    PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome PUPPETEER_CACHE_DIR=./puppeteer-cache PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors javascript // 环境变量使用 const puppeteer = require(‘puppeteer’); const browser = await puppeteer.launch({ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH, headless: process.env.NODE_ENV === ‘production’ }); “`

    1.5 第一个Puppeteer程序

    1.5.1 Hello World示例

    javascript // src/hello-world.js const puppeteer = require('puppeteer'); (async () => { console.log('启动Puppeteer Hello World程序...'); // 启动浏览器 const browser = await puppeteer.launch({ headless: false, defaultViewport: null, args: ['--start-maximized'] }); // 创建新页面 const page = await browser.newPage(); // 导航到Google await page.goto('https://www.google.com'); // 等待搜索框加载 await page.waitForSelector('input[name="q"]'); // 输入搜索内容 await page.type('input[name="q"]', 'Puppeteer教程'); // 按回车搜索 await page.keyboard.press('Enter'); // 等待搜索结果 await page.waitForSelector('#search'); // 截图保存 await page.screenshot({ path: 'hello-world.png', fullPage: true }); console.log('搜索完成,截图已保存为 hello-world.png'); // 等待3秒后关闭 await page.waitForTimeout(3000); await browser.close(); console.log('程序执行完成'); })();

    1.5.2 网页信息提取示例

    javascript // src/extract-info.js const puppeteer = require('puppeteer'); const extractPageInfo = async (url) => { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); try { await page.goto(url, { waitUntil: 'networkidle2' }); // 提取页面信息 const pageInfo = await page.evaluate(() => { return { title: document.title, url: window.location.href, description: document.querySelector('meta[name="description"]')?.content || '', keywords: document.querySelector('meta[name="keywords"]')?.content || '', headings: Array.from(document.querySelectorAll('h1, h2, h3')).map(h => ({ tag: h.tagName, text: h.textContent.trim() })), links: Array.from(document.querySelectorAll('a[href]')).slice(0, 10).map(a => ({ text: a.textContent.trim(), href: a.href })), images: Array.from(document.querySelectorAll('img[src]')).slice(0, 5).map(img => ({ alt: img.alt, src: img.src })) }; }); return pageInfo; } catch (error) { console.error('提取页面信息失败:', error); return null; } finally { await browser.close(); } }; // 使用示例 (async () => { const urls = [ 'https://example.com', 'https://github.com', 'https://stackoverflow.com' ]; for (const url of urls) { console.log(`\n正在分析: ${url}`); const info = await extractPageInfo(url); if (info) { console.log('页面标题:', info.title); console.log('页面描述:', info.description); console.log('标题数量:', info.headings.length); console.log('链接数量:', info.links.length); console.log('图片数量:', info.images.length); } } })();

    1.5.3 表单自动填写示例

    javascript // src/form-automation.js const puppeteer = require('puppeteer'); const automateForm = async () => { const browser = await puppeteer.launch({ headless: false, slowMo: 100 }); const page = await browser.newPage(); try { // 导航到表单页面 await page.goto('https://httpbin.org/forms/post'); // 填写表单字段 await page.type('input[name="custname"]', '张三'); await page.type('input[name="custtel"]', '13800138000'); await page.type('input[name="custemail"]', 'zhangsan@example.com'); // 选择下拉框 await page.select('select[name="size"]', 'large'); // 选择单选按钮 await page.click('input[name="topping"][value="bacon"]'); // 选择复选框 await page.click('input[name="delivery"][value="11:15"]'); // 填写文本域 await page.type('textarea[name="comments"]', '这是一个自动化测试表单'); // 提交表单 await page.click('input[type="submit"]'); // 等待结果页面 await page.waitForNavigation(); // 获取提交结果 const result = await page.evaluate(() => { return document.body.textContent; }); console.log('表单提交成功,结果:', result); } catch (error) { console.error('表单自动化失败:', error); } finally { await browser.close(); } }; automateForm();

    1.6 常见问题与解决方案

    1.6.1 安装问题

    问题1:Chromium下载失败

    ”`bash

    解决方案1:使用国内镜像

    npm config set puppeteer_download_host https://npm.taobao.org/mirrors npm install puppeteer

    解决方案2:跳过Chromium下载

    PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm install puppeteer-core “`

    问题2:权限错误

    ”`bash

    Linux/macOS权限问题

    sudo chown -R $(whoami) ~/.npm sudo chown -R $(whoami) /usr/local/lib/node_modules

    或者使用nvm管理Node.js版本

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash nvm install node “`

    1.6.2 运行时问题

    问题1:浏览器启动失败

    javascript // 解决方案:添加启动参数 const browser = await puppeteer.launch({ args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-accelerated-2d-canvas', '--no-first-run', '--no-zygote', '--single-process', '--disable-gpu' ] });

    问题2:页面加载超时

    javascript // 解决方案:增加超时时间和等待策略 await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 }); // 或者使用自定义等待 await page.waitForFunction( () => document.readyState === 'complete', { timeout: 30000 } );

    问题3:内存不足

    javascript // 解决方案:限制并发和清理资源 const cluster = require('cluster'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { // 限制工作进程数量 for (let i = 0; i < Math.min(numCPUs, 4); i++) { cluster.fork(); } } else { // 工作进程中运行Puppeteer const runPuppeteer = async () => { const browser = await puppeteer.launch(); // ... 执行任务 await browser.close(); process.exit(0); }; runPuppeteer(); }

    1.7 开发工具与调试

    1.7.1 开发工具配置

    VS Code配置

    json // .vscode/launch.json { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug Puppeteer", "program": "${workspaceFolder}/src/index.js", "env": { "NODE_ENV": "development" }, "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] }

    ESLint配置

    json // .eslintrc.json { "env": { "node": true, "es2021": true }, "extends": ["eslint:recommended"], "parserOptions": { "ecmaVersion": 12, "sourceType": "module" }, "rules": { "no-console": "off", "no-unused-vars": "warn" } }

    1.7.2 调试技巧

    启用调试模式

    javascript // 调试模式启动 const browser = await puppeteer.launch({ headless: false, devtools: true, slowMo: 250, args: ['--auto-open-devtools-for-tabs'] }); // 页面调试 const page = await browser.newPage(); // 启用控制台日志 page.on('console', msg => { console.log('页面日志:', msg.text()); }); // 启用错误监听 page.on('pageerror', error => { console.error('页面错误:', error.message); }); // 启用请求监听 page.on('request', request => { console.log('请求:', request.url()); });

    断点调试

    javascript // 在代码中添加断点 const debugPage = async () => { const browser = await puppeteer.launch({ headless: false, devtools: true }); const page = await browser.newPage(); await page.goto('https://example.com'); // 暂停执行,等待手动操作 await page.evaluate(() => { debugger; // 浏览器断点 }); // Node.js断点 debugger; await browser.close(); };

    1.8 本章小结

    通过本章的学习,我们了解了:

    核心概念

  • Puppeteer基础:Google开发的Node.js库,用于控制Chrome/Chromium浏览器

  • 主要组件:Browser、Page、ElementHandle等核心对象

  • 工作原理:通过DevTools协议与浏览器通信

    环境搭建

  • 系统要求:Node.js 14+、现代操作系统、足够的内存和存储

  • 安装配置:npm安装、环境变量配置、TypeScript支持

  • 项目结构:合理的目录组织和配置文件

    基础应用

  • 浏览器控制:启动、配置、多页面管理

  • 页面操作:导航、交互、数据提取

  • 调试技巧:开发工具配置、错误处理、性能优化

    最佳实践

  • 配置优化:合理的启动参数和页面设置

  • 错误处理:完善的异常捕获和资源清理

  • 性能考虑:内存管理、并发控制、超时设置

    下一章预告

    在下一章《浏览器控制与页面操作》中,我们将深入学习:

  • 浏览器实例的高级管理

  • 页面生命周期控制

  • 复杂的页面交互操作

  • 多页面协调和数据共享

  • 浏览器扩展和插件集成 — 练习作业

  1. 搭建完整的Puppeteer开发环境
  2. 编写一个页面信息提取工具
  3. 实现一个简单的表单自动化脚本
  4. 配置调试环境并熟悉调试技巧 继续学习,掌握更多Puppeteer的强大功能!