Puppeteer:94,300 个 GitHub Stars

Puppeteer 是一个用于无头 Chrome 和 Firefox 自动化的 Node.js 库,支持 Docker、GitHub Actions、Jest、Mocha、TypeScript。涵盖 puppeteer Docker 部署、生产环境上线、浏览器自动化教程和 CI/CD 集成。

  • ⭐ 7366
  • Python
  • Apache-2.0
  • 更新于 2026-05-19

LazyDocker:51,092 个 GitHub StarsGrafana:74,380 个 GitHub Stars — 2026 Docker 部署指南

简介 #

大规模跑浏览器自动化,意味着要跟 Chrome 崩溃、无头环境的内存泄漏,以及页面加载间不稳定的选择器较劲。Puppeteer 由 Google 的 Chrome DevTools 团队维护,提供了一套高层级的 Node.js API,通过 DevTools Protocol 和 WebDriver BiDi 控制 Chrome 和 Firefox。凭借 94,300 个 GitHub Star、540+ 贡献者和每周 490 万次 npm 下载量,它依然是需要在生产环境里做可靠、可编程浏览器控制的团队的首选库。

这篇 puppeteer 教程会带你走完一套完整的浏览器自动化配置——从跑通 puppeteer docker 部署到 CI/CD 集成——附带真实配置、性能数据和坦诚的权衡取舍。无论你是要生成 PDF、抓取 SPA,还是跑端到端回归测试,这些 puppeteer 生产环境模式都能直接用上。

Puppeteer 是什么? #

Puppeteer 是一个 Node.js 库,提供一套编程 API,通过 Chrome DevTools Protocol (CDP) 和 WebDriver BiDi 控制 Chrome、Chromium 和 Firefox。它默认以无头模式运行,适合服务器环境,但在需要调试时也能驱动可见(“有头”)浏览器窗口。这个项目在 2017 年发布首个公开版本,此后成长为一个横跨网页抓取、PDF 生成、截图自动化、无障碍测试和 CI/CD 流水线的生态系统。

puppeteer 包会在安装时自动打包 Chromium,而 puppeteer-core 省略了浏览器下载——这个区别在 Docker 等你自己提供 Chrome 二进制文件的受限环境里很重要。

Puppeteer 是怎么工作的 #

Puppeteer 架构图

Puppeteer GitHub 仓库显示 94,300 个 Star

Puppeteer 通过 WebSocket 连接和浏览器通信。当你调用 puppeteer.launch() 时,这个库会启动一个开启了远程调试功能的 Chrome 或 Firefox 进程(监听本地端口),然后通过 DevTools Protocol 连接上它。这种直连方式避免了老式基于 WebDriver 的工具所需的 HTTP 往返开销。

关键架构概念:

  • Browser(浏览器):一个正在运行的浏览器实例。你可以并行运行多个来实现隔离。
  • Page(页面):相当于一个浏览器标签页。大多数自动化代码都在和 Page 对象打交道。
  • Context(上下文):浏览器上下文提供一个隔离的会话——独立的 Cookie、localStorage 和缓存。可以理解为一个隐身窗口。
  • CDP Session(CDP 会话):对 Chrome DevTools Protocol 的底层访问,用于网络拦截、性能追踪、覆盖率报告等高级场景。

从 v25.0.0(2026 年 5 月)开始,Puppeteer 改为仅支持 ESM 模块,最低 Node.js 版本要求提升到 22。这去掉了 CommonJS 支持,转而拥抱原生 ES 模块,与更广泛的 Node.js 生态保持一致。

安装与配置 #

在装有 Node.js 22+ 的机器上,本地安装 Puppeteer 用不了三分钟。

# 安装并打包 Chromium
npm install puppeteer

# 或者用 puppeteer-core,自己管理 Chrome
npm install puppeteer-core

用一个最小脚本验证安装

// quickstart.mjs —— 验证 Puppeteer 能正常启动
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const title = await page.title();
console.log(`Page title: ${title}`);
await browser.close();

运行它:

node quickstart.mjs
# 预期输出:Page title: Example Domain

对于自己独立管理 Chrome 的环境——Docker、AWS Lambda,或预装了 Chromium 的系统——用 puppeteer-core 并设置 executablePath

import puppeteer from 'puppeteer-core';

const browser = await puppeteer.launch({
  executablePath: '/usr/bin/chromium',
  headless: 'new',
  args: ['--no-sandbox', '--disable-setuid-sandbox']
});

Docker 部署 #

在 Docker 里跑 Puppeteer 能消除"在我机器上明明能跑"的问题,让开发、预发布和生产环境的部署保持一致。挑战在于 Chromium 需要特定的系统库——少装一个,浏览器就会报出难以理解的启动错误。

生产环境 Dockerfile:

# Dockerfile —— 搭配 Chromium 的 Node.js 22,用于 Puppeteer
FROM node:22-slim

# 安装 Chromium 依赖和字体
RUN apt-get update && apt-get install -y --no-install-recommends \
    chromium \
    fonts-liberation \
    libappindicator3-1 \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libgbm1 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libx11-xcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxrandr2 \
    xdg-utils \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# 使用系统自带的 Chromium,跳过打包下载
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

# 创建非 root 用户以保证安全
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
    && mkdir -p /home/pptruser/app \
    && chown -R pptruser:pptruser /home/pptruser

WORKDIR /home/pptruser/app

# 安装依赖
COPY package.json package-lock.json ./
RUN npm ci --production

# 拷贝应用代码
COPY src/ ./src/
USER pptruser

CMD ["node", "src/index.mjs"]

构建并运行:

docker build -t puppeteer-app .
docker run --rm -v $(pwd)/output:/home/pptruser/app/output puppeteer-app

本地开发用的 docker-compose.yml:

version: '3.8'
services:
  puppeteer:
    build: .
    volumes:
      - ./src:/home/pptruser/app/src
      - ./output:/home/pptruser/app/output
    environment:
      - NODE_ENV=production
      - PUPPETEER_ARGS=--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage
    shm_size: '2gb'
    deploy:
      resources:
        limits:
          memory: 4G
        reservations:
          memory: 1G

shm_size 这个设置至关重要。Chrome 用 /dev/shm 做共享内存,Docker 容器默认给的 64MB 在处理大页面时会导致崩溃。设为 2GB 能避免无头模式下的"Aw, snap"错误。

Puppeteer Docker 容器运行无头 Chrome

Docker 资源限制和 Chrome 参数,用于稳定的无头运行。

核心自动化模式 #

抓取动态内容 #

现代 SPA 会在初始 HTML 响应之后才加载内容。Puppeteer 会先等待选择器出现,再提取数据:

// scraper.mjs —— 从 JavaScript 渲染的页面提取数据
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();

await page.setViewport({ width: 1366, height: 768 });
await page.setUserAgent(
  'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36'
);

await page.goto('https://quotes.toscrape.com/js/', {
  waitUntil: 'networkidle2',
  timeout: 30000
});

// 等待动态内容渲染完成
await page.waitForSelector('.quote', { timeout: 10000 });

const quotes = await page.evaluate(() => {
  return Array.from(document.querySelectorAll('.quote')).map(el => ({
    text: el.querySelector('.text')?.textContent?.trim(),
    author: el.querySelector('.author')?.textContent?.trim(),
    tags: Array.from(el.querySelectorAll('.tag')).map(t => t.textContent.trim())
  }));
});

console.log(`Scraped ${quotes.length} quotes`);
await browser.close();

截图和 PDF 生成 #

Puppeteer 非常擅长从 HTML 渲染视觉产物——这在发票、报表和 Open Graph 卡片图生成场景中很常见:

// screenshot.mjs —— 全页截图和 PDF 导出
import puppeteer from 'puppeteer';
import fs from 'fs';
import path from 'path';

const OUTPUT_DIR = './output';
fs.mkdirSync(OUTPUT_DIR, { recursive: true });

const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();

await page.setViewport({ width: 1280, height: 800 });

// 截图:全页 PNG
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.screenshot({
  path: path.join(OUTPUT_DIR, 'page.png'),
  fullPage: true
});

// PDF:A4,带背景图形
await page.pdf({
  path: path.join(OUTPUT_DIR, 'page.pdf'),
  format: 'A4',
  printBackground: true,
  margin: { top: '1cm', right: '1cm', bottom: '1cm', left: '1cm' }
});

console.log('Screenshot and PDF saved to', OUTPUT_DIR);
await browser.close();

网络拦截与请求屏蔽 #

在抓取场景中,屏蔽不必要的资源能把页面加载时间缩短 40-60%:

// blocker.mjs —— 屏蔽图片和 CSS 以加快抓取速度
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: 'new' });
const page = await browser.newPage();

// 拦截并屏蔽图片/样式表/媒体请求
await page.setRequestInterception(true);
page.on('request', (req) => {
  const block = ['image', 'stylesheet', 'font', 'media'];
  if (block.includes(req.resourceType())) {
    req.abort();
  } else {
    req.continue();
  }
});

const start = Date.now();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log(`Loaded in ${Date.now() - start}ms (resources blocked)`);

await browser.close();

与主流工具集成 #

GitHub Actions #

在每次 push 时自动截图或跑回归测试:

# .github/workflows/puppeteer.yml
name: Puppeteer CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  puppeteer:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Puppeteer tests
        run: npm test
        env:
          CI: true
          PUPPETEER_ARGS: '--no-sandbox --disable-setuid-sandbox'

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: screenshots
          path: output/*.png

Jest 测试框架 #

// jest.config.js
module.exports = {
  testEnvironment: 'node',
  testMatch: ['**/*.test.mjs'],
  testTimeout: 30000,
  globals: {
    'ts-jest': { useESM: true }
  }
};
// homepage.test.mjs —— Jest + Puppeteer 集成
import puppeteer from 'puppeteer';

describe('Homepage', () => {
  let browser;
  let page;

  beforeAll(async () => {
    browser = await puppeteer.launch({
      headless: 'new',
      args: (process.env.PUPPETEER_ARGS || '').split(' ').filter(Boolean)
    });
    page = await browser.newPage();
  });

  afterAll(async () => {
    await browser.close();
  });

  test('page title is correct', async () => {
    await page.goto('https://example.com');
    const title = await page.title();
    expect(title).toBe('Example Domain');
  });

  test('navigation loads within 3 seconds', async () => {
    const start = Date.now();
    await page.goto('https://example.com', { waitUntil: 'networkidle2' });
    expect(Date.now() - start).toBeLessThan(3000);
  });
});

TypeScript 配置 #

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}
// src/scraper.ts —— TypeScript 搭配 Puppeteer
import puppeteer, { Browser, Page } from 'puppeteer';

interface Product {
  name: string;
  price: string;
  url: string;
}

async function scrapeProducts(url: string): Promise<Product[]> {
  const browser: Browser = await puppeteer.launch({ headless: 'new' });
  const page: Page = await browser.newPage();

  await page.goto(url, { waitUntil: 'networkidle2' });

  const products: Product[] = await page.evaluate(() => {
    return Array.from(document.querySelectorAll('.product')).map(el => ({
      name: el.querySelector('.name')?.textContent?.trim() || '',
      price: el.querySelector('.price')?.textContent?.trim() || '',
      url: el.querySelector('a')?.href || ''
    }));
  });

  await browser.close();
  return products;
}

const results = await scrapeProducts('https://example.com/products');
console.log(`Found ${results.length} products`);

Mocha 测试运行器 #

// .mocharc.cjs
module.exports = {
  extension: ['mjs'],
  spec: 'test/**/*.test.mjs',
  timeout: 30000,
  exit: true
};
// test/scraper.test.mjs —— Mocha + Puppeteer
import puppeteer from 'puppeteer';
import assert from 'assert';

describe('Scraper Suite', function() {
  this.timeout(30000);

  let browser;
  before(async () => {
    browser = await puppeteer.launch({
      headless: 'new',
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });
  });

  after(async () => await browser.close());

  it('should extract product data', async () => {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    const heading = await page.$eval('h1', el => el.textContent);
    assert.strictEqual(heading, 'Example Domain');
    await page.close();
  });
});

性能基准测试 / 真实使用场景 #

独立基准测试显示,在以 Chrome 为核心的场景下,Puppeteer 依然占据强势位置:

指标PuppeteerSeleniumPlaywrightCypress
平均操作延迟< 1 秒3-5 秒1-2 秒1-2 秒
配置耗时10-15 分钟2-4 小时15-30 分钟15-30 分钟
通过率(100 次运行)93%84%94%96%
单实例内存占用200-400MB300-500MB250-450MB400-600MB
测试套件(50 个测试)顺序 2 分 55 秒 / 并行 48 秒顺序 8 分 45 秒 / 并行 2 分 50 秒顺序 3 分 20 秒 / 并行 52 秒顺序 3 分 45 秒 / 并行 1 分 10 秒
每月维护成本约 11 小时约 16.5 小时约 12 小时约 10.5 小时

什么时候该选 Puppeteer 而不是其他方案:

  • PDF 生成和截图流水线:Puppeteer 的 page.pdf()page.screenshot() 是浏览器自动化领域最成熟的 API。
  • Chrome DevTools Protocol 访问:对于要构建开发者工具、性能分析器或覆盖率报告工具的团队,直接 CDP 访问是只有 Puppeteer 原生满足的需求。
  • 大规模网页抓取:搭配 Bull 或 RabbitMQ 这样的任务队列,Puppeteer 能以极低开销每小时处理数千个 URL。
  • 已有 Node.js 基础设施:如果你的后端已经是 TypeScript/JavaScript,引入 Puppeteer 不会带来任何新的运行时或语言。

进阶用法 / 生产环境加固 #

浏览器池管理 #

每个请求都启动一个新浏览器很浪费。连接池能复用浏览器实例:

// pool.mjs —— 带最大并发限制的可复用浏览器池
import puppeteer from 'puppeteer';

class BrowserPool {
  constructor(maxBrowsers = 5) {
    this.maxBrowsers = maxBrowsers;
    this.pool = [];
    this.queue = [];
  }

  async init() {
    for (let i = 0; i < this.maxBrowsers; i++) {
      const browser = await puppeteer.launch({
        headless: 'new',
        args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
      });
      this.pool.push({ browser, inUse: false });
    }
  }

  async acquire() {
    const available = this.pool.find(b => !b.inUse);
    if (available) {
      available.inUse = true;
      return available.browser;
    }
    return new Promise(resolve => this.queue.push(resolve));
  }

  release(browser) {
    const entry = this.pool.find(b => b.browser === browser);
    if (entry) {
      entry.inUse = false;
      if (this.queue.length > 0) {
        const next = this.queue.shift();
        entry.inUse = true;
        next(entry.browser);
      }
    }
  }

  async close() {
    await Promise.all(this.pool.map(b => b.browser.close()));
  }
}

const pool = new BrowserPool(3);
await pool.init();

const browser = await pool.acquire();
const page = await browser.newPage();
await page.goto('https://example.com');
// …… 干活 ……
await page.close();
pool.release(browser);

优雅的错误处理与重试 #

生产环境的抓取任务会遇到网络超时、反爬检测和临时故障。用指数退避包装页面导航:

// retry.mjs —— 带指数退避的健壮导航
async function gotoWithRetry(page, url, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await page.goto(url, {
        waitUntil: 'networkidle2',
        timeout: 30000
      });
      return;
    } catch (err) {
      if (attempt === maxRetries) throw err;
      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

健康监控 #

在长期运行的服务中,监控浏览器进程健康状态,并重启崩溃的实例:

// health.mjs —— 浏览器进程的基础健康检查
async function isBrowserHealthy(browser) {
  try {
    const version = await browser.version();
    return !!version;
  } catch {
    return false;
  }
}

// 每 60 秒定期检查
setInterval(async () => {
  for (const entry of pool.pool) {
    const healthy = await isBrowserHealthy(entry.browser);
    if (!healthy) {
      console.warn('Unhealthy browser detected, restarting...');
      await entry.browser.close();
      entry.browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox'] });
      entry.inUse = false;
    }
  }
}, 60000);

与其他方案对比 #

特性PuppeteerSeleniumPlaywrightCypress
主要语言JavaScript, TypeScriptJava, Python, C#, JS, RubyJS/TS, Python, Java, .NETJavaScript, TypeScript
浏览器支持Chrome, Chromium, Firefox所有主流 + 移动端 (Appium)Chromium, Firefox, WebKitChromium, Edge, Firefox
协议CDP, WebDriver BiDiW3C WebDriverCDP, WebDriver BiDi浏览器内执行
执行速度极快 (< 1秒/操作)慢 (3-5秒/操作)快 (1-2秒/操作)快 (1-2秒/操作)
内置测试运行器无(用 Jest/Mocha)无(用外部工具)有 (playwright test)
并行执行手动配置Selenium Grid内置 workerCypress Cloud(付费)
PDF 生成原生 (page.pdf)第三方原生第三方插件
移动端模拟Chrome 设备模拟完整支持(通过 Appium)视口模拟
社区 / GitHub Star94,30034,00078,00048,000
协议Apache-2.0Apache-2.0Apache-2.0MIT
最适合抓取、PDF、截图企业、多语言场景跨浏览器测试前端开发者测试

选型建议: 如果你的工作以 Chrome 自动化为核心——抓取、PDF 生成、截图流水线,或 DevTools 集成——选 Puppeteer。如果你需要在单个测试套件里覆盖 Chromium、Firefox 和 WebKit 的跨浏览器测试,Playwright 能力更全面。对 Java/.NET 团队或传统企业环境来说,Selenium 依然是默认选择。Cypress 适合把开发者体验和可视化调试看得比原始执行速度更重要的 JavaScript 团队。

局限性 / 真实评估 #

Puppeteer 并不是每种浏览器自动化任务的最佳选择。投入使用前先考虑这些限制:

  • 仅限 JavaScript:Puppeteer 是一个 Node.js 库。用 Python、Java 或 Go 的团队只能用 pyppeteer(非官方,更新滞后)或转向 Selenium/Playwright。
  • 跨浏览器支持有限:虽然通过 WebDriver BiDi 支持 Firefox,但成熟度不如 Chrome 自动化。不支持 Safari 和 WebKit。如果跨浏览器测试是硬需求,Playwright 原生覆盖全部三种渲染引擎。
  • 没有内置测试运行器:不像 Cypress 或 Playwright,Puppeteer 不自带断言、测试组织或报告工具,需要你自己搭配 Jest、Mocha 或 Vitest。
  • 并行化需要手动实现:并行测试执行需要手动管理浏览器池或借助外部编排工具。对大型测试套件来说,Playwright 内置的 worker 模型更简单。
  • 内存占用:每个 Chrome 实例消耗 200-400MB 内存。并发抓取数千个页面需要相当规模的基础设施或基于集群的方案。
  • 反爬检测:现代网站用 Cloudflare、DataDome 和 PerimeterX 检测无头浏览器。仅靠 Puppeteer 本身绕不过这些系统——需要额外用上 puppeteer-extra-plugin-stealth 之类的工具,且效果参差不齐。

常见问题 #

puppeteerpuppeteer-core 有什么区别? #

puppeteer 包会在安装时打包并下载 Chromium。puppeteer-core 包只包含 JavaScript API,期望你通过 executablePath 启动参数提供 Chrome 或 Chromium 可执行文件。在 Docker、CI/CD 流水线,以及自己管理浏览器二进制文件的环境里,用 puppeteer-core

Puppeteer 支持 Firefox 吗? #

支持,自 2023 年起 Puppeteer 通过 WebDriver BiDi 协议支持 Firefox。不过 Firefox 支持的成熟度不如 Chrome 自动化。一些 CDP 专属功能,比如性能追踪和覆盖率报告,仅限 Chrome。如果生产工作负载要面向 Firefox,Playwright 可能提供更广泛的 API 对等能力。

怎么在 Docker 里以非 root 权限运行 Puppeteer? #

在 Dockerfile 里创建一个专属的非 root 用户,把它加入 audiovideo 用户组,然后用 --no-sandbox--disable-setuid-sandbox 参数运行 Chrome。本指南里的示例 Dockerfile 展示了完整配置。注意 --no-sandbox 会降低进程隔离性,但在容器化环境里,容器本身提供了安全边界,这个权衡是可以接受的。

Puppeteer 25 最低需要什么 Node.js 版本? #

Puppeteer v25.0.0 及之后的版本要求 Node.js 22 或更高。这个版本改成了仅支持 ESM 模块,不再支持 CommonJS 的 require()。如果你用的是 Node.js 18 或 20,安装 Puppeteer 25 前先升级,或者锁定在支持 Node.js 18+ 的 Puppeteer 24.x。

怎么降低 Puppeteer 生产部署的内存占用? #

用浏览器池限制并发 Chrome 实例数量,通过请求拦截屏蔽图片、CSS、字体等不必要的资源,用完页面立刻关闭,并设置 --disable-dev-shm-usage 参数,改用 /tmp 而不是 /dev/shm 做共享内存。在 Docker 里,把 shm_size 提高到至少 2GB,防止渲染进程崩溃。

Puppeteer 适合大规模网页抓取吗? #

搭配合适的基础设施,Puppeteer 能应对大规模抓取。一台 4GB 内存的机器上,单个 Node.js 进程能管理 3-5 个并发 Chrome 实例。要获得更高吞吐量,用消息队列(Redis、RabbitMQ、SQS)把工作分发到多个容器或虚拟机上。要注意很多网站会主动屏蔽无头浏览器,所以生产抓取流水线要把 Puppeteer 和代理轮换、指纹随机化结合起来使用。

Puppeteer 和 Playwright 在测试场景下比怎么样? #

Puppeteer 和 Playwright 师出同门——Playwright 团队最初就是在 Google 打造了 Puppeteer,后来才转到微软。Playwright 追加了跨浏览器支持(WebKit/Safari)、内置测试运行器、自动等待和移动设备模拟。以 Chrome 为核心的自动化和抓取选 Puppeteer。需要最广泛浏览器覆盖的跨浏览器端到端测试选 Playwright。

结语 #

对于需要以编程方式控制 Chrome 的团队,Puppeteer 依然是稳妥之选。它的 94,300 个 GitHub Star,加上 Chrome DevTools 团队的持续维护,标志着长期稳定性。在 PDF 生成、截图流水线和基于 Chrome 的抓取场景,这个库的 API 覆盖面无可匹敌。本指南中的 Docker 模式、浏览器池管理和重试逻辑,为生产环境提供了一套可用的基础方案。

行动清单:

  1. 克隆官方 Puppeteer 示例,把抓取模式适配到你的目标网站上。
  2. 用本指南中的 Dockerfile 构建镜像,在预发布环境里跑起来。
  3. 配置 GitHub Actions 工作流,在每次 PR 时自动截图或跑回归测试。
  4. 加入 dibi8 Telegram 群,分享你的 Puppeteer 部署经验,也能从其他跑大规模浏览器自动化的开发者那里获得帮助。

推荐的托管与基础设施 #

在把上面这些工具部署到生产环境之前,你需要靠谱的基础设施。以下两个是 dibi8 实际在用、并推荐的方案:

  • DigitalOcean — 60 天 200 美元免费额度,覆盖 14+ 全球区域。独立开发者跑开源 AI 工具的默认选择。
  • HTStack — 香港 VPS,大陆访问低延迟。dibi8.com 本身就托管在这家 IDC——生产环境实测过硬。

以上为联盟链接——不会让你多花一分钱,但能帮 dibi8.com 持续运营下去。

来源与延伸阅读 #

参考与来源 #

💬 留言讨论