Puppeteer学习笔记

Puppeteer学习笔记

2025年06月07日 阅读:2 字数:1054 阅读时长:3 分钟

使用Puppeteer进行自动化测试、爬取数据。

1. 简介

Puppeteer 是一个由谷歌 Chrome 开发团队发布的 Node.js 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。

1.1. 主要功能

  • 生成截图和PDF:可以生成页面的屏幕截图和 PDF。
  • 抓取和预渲染:能够抓取单页应用(SPA)并生成预渲染内容,即服务器端渲染(SSR)。
  • 自动化测试:可以自动提交表单、进行 UI 测试、模拟键盘输入等,创建自动化测试环境。
  • 性能分析:捕获站点的时间线跟踪,帮助诊断性能问题。
  • 测试浏览器扩展:支持测试 Chrome 扩展程序。

1.2. 使用场景

  • 前端自动化测试:帮助前端工程师快速测试和优化前端代码。
  • 爬虫:用于网络爬虫,获取网页数据。
  • 页面渲染:用于服务器端渲染,提高页面加载速度

2. 示例笔记

import puppeteer, { Browser, Frame, Page } from 'puppeteer'

// 启动浏览器
const browser = await puppeteer.launch({
  headless: true,
  // userDataDir: '../storage',  // 是否需要存储数据
  args: ['--no-sandbox']
})

// 新建页面
const page = await browser.newPage()

// 跳转到新页面
await page.goto('https://www.timelessq.com')

2.1. 查找元素

const usernameInput = page.locator(`input[type='text']`)
const passwordInput = page.locator(`input[type='password']`)
const $username = await usernameInput.waitHandle()
const $password = await passwordInput.waitHandle()

// 或者使用waitForSelector
const $login = await page.waitForSelector(`::-p-xpath(//span[text()='登录'])`, {
  timeout: 3000,
})

// $$
const $container = (await page.$$(`div[class='layout'] > div`)).at(-1)

2.2. 操作

// 输入用户名
await $username.click()
await $username.type(email, { delay: 100 })

// 输入密码
await $pwd.click()
await $pwd.type(password, { delay: 100 })

// 获取文本内容
const text = await option.evaluate((el) => el.innerText)

2.3. 截图

const $bgImg = await page.waitForSelector("img[id='captcha_verify_image']")
const backgroundImg = await $bgImg.screenshot({ encoding: 'base64' })

2.4. 获取请求响应

const response = await page.waitForResponse(
  (response) => response.url().includes('https://api.timelessq.com/time') && response.status() === 200,
)
const result = await response.json()

2.5. 拖动验证码

import { BoundingBox, Page } from 'puppeteer'


// 缓动函数(easeOutQuad)
function easeOutQuad(t: number): number {
  return t * (2 - t)
}

// 生成人类化轨迹
function generateHumanTrajectory(distance: number, steps: number = 30): { x: number; y: number }[] {
  const trajectory: { x: number; y: number }[] = []
  let current = 0
  let prevPosition = 0

  for (let i = 0; i < steps; i++) {
    const t = i / (steps - 1)
    const eased = easeOutQuad(t)
    const newPosition = eased * distance

    // 添加随机扰动(幅度逐渐减小)
    const randomFactor = 1 - t // 越到后期扰动越小
    const deltaX = newPosition - prevPosition
    const deltaY = (Math.random() * 4 - 2) * randomFactor // Y轴扰动

    trajectory.push({
      x: deltaX,
      y: deltaY,
    })

    prevPosition = newPosition
    current = newPosition
  }

  // 精度补偿确保最终到达目标
  const totalX = trajectory.reduce((sum, step) => sum + step.x, 0)
  const diff = distance - totalX
  if (Math.abs(diff) > 0.001) {
    trajectory[steps - 1].x += diff
  }

  return trajectory
}

// 执行人类化拖动
function humanDrag(page: Page, sliderBox: BoundingBox, distance: number): Promise<void> {
  const startPoint = {
    x: sliderBox.x + sliderBox.width / 2,
    y: sliderBox.y + sliderBox.height / 2,
  }

  // 加入初始随机偏移
  await page.mouse.move(startPoint.x + Math.random() * 3 - 1.5, startPoint.y + Math.random() * 3 - 1.5, { steps: 5 })
  await page.mouse.down()

  const trajectory = generateHumanTrajectory(distance)
  let currentPosition = { ...startPoint }

  for (const [index, step] of trajectory.entries()) {
    currentPosition.x += step.x
    currentPosition.y += step.y

    // 添加非匀速移动效果
    const moveSteps = index < trajectory.length / 2 ? 5 : 10
    await page.mouse.move(currentPosition.x + Math.random() * 2 - 1, currentPosition.y + Math.random() * 2 - 1, {
      steps: moveSteps,
    })

    // 动态间隔时间(前期快后期慢)
    const baseDelay = index < trajectory.length / 2 ? 20 : 40
    await delay(baseDelay + Math.random() * 30)

    // 随机添加停顿
    if (Math.random() < 0.2) {
      await delay(50 + Math.random() * 100)
    }
  }

  // 最终微调(模拟人类修正行为)
  for (let i = 0; i < 2; i++) {
    await page.mouse.move(currentPosition.x + (Math.random() * 2 - 1), currentPosition.y + (Math.random() * 2 - 1), {
      steps: 3,
    })
    await delay(50)
  }

  await page.mouse.up()
}

3. 常见问题

3.1. Linux安装缺少依赖

安装完puppeteer后,到/root/.cache/puppeteer/chrome/linux-xxxxx/chrome-linux64/目录下,执行 ldd chrome | grep not 以检查缺少哪些依赖。

比如,我的服务器就输出:

libglib-2.0.so.0 => not found
libgobject-2.0.so.0 => not found
libgio-2.0.so.0 => not found
libatk-1.0.so.0 => not found
libatk-bridge-2.0.so.0 => not found
libcups.so.2 => not found
libxkbcommon.so.0 => not found
libatspi.so.0 => not found
libXcomposite.so.1 => not found
libXdamage.so.1 => not found
libXfixes.so.3 => not found
libXrandr.so.2 => not found
libgbm.so.1 => not found
libpango-1.0.so.0 => not found
libcairo.so.2 => not found
libasound.so.2 => not found

然后把这个丢给ai分析,或者搜索看缺少哪些依赖包,然后使用apt安装依赖

apt install libglib2.0-0 libatk1.0-0 libatk-bridge2.0-0 libcups2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound2

3.2. sandbox

使用root运行,sandbox报错

const browser = await puppeteer.launch({
  headless: true,
  args: [
    '--no-sandbox'
  ]
})

 

4. 参考文档

推荐阅读

恰饭区

评论区 (0)

0/500

还没有评论,快来抢第一吧