教程
Shotomatic Team
约 18 分钟阅读

如何用 Playwright 自动截取网站截图

使用 Playwright 和 JavaScript 自动截取网站截图,包括单页、整页、移动端视图,以及带重试机制的 URL 批量截图。

笔记本电脑上显示网站自动截图脚本代码

本文会分阶段编写 Playwright 截图脚本:先截取单个视口,再截取整页,然后制作可重复使用的 URL 执行器,最后加入移动端视口。

如果截图需要与驱动它们的代码放在一起,Playwright 很合适。它提供真实浏览器渲染、相互隔离的浏览器上下文、明确的视口控制、设备模拟,以及等待目标页面状态的接口。

示例都以 Shotomatic 功能页 https://www.shotomatic.com/features 为目标,因此可以比较同一页面的视口截图、整页截图、可批量运行版本和移动端截图。

**简而言之:**截图自动化本来就应该写进代码时,用 Playwright。创建浏览器上下文,设置视口或设备,等待所需的页面状态,再调用 page.screenshot();随后加入整页截图、批量处理、重试和报告。如果不想承担这套脚本的编写与维护工作,Shotomatic Website Capture可能更简单。

说明:我们开发了 Shotomatic,因此示例采用我们的公开功能页。Playwright 也能截取你获准处理的其他公开网站。如果需要的是无代码 URL 列表截图,请使用 Shotomatic Website Capture

适合使用 Playwright 的情况

截图必须遵循浏览器逻辑时,请用 Playwright。

以下情况适合使用:

  • 在 CI 中截取截图;
  • 截图前需要登录;
  • 等待特定选择器或应用状态;
  • 在 Chromium、Firefox 或 WebKit 上运行同一项截图任务;
  • 根据明确的视口设置制作响应式截图;
  • 在内部工具中生成截图。

需要截图的人不是脚本维护者时,使用起来就没那么方便。如果这项工作应该由代码负责,Playwright 是不错的起点。

为截图脚本安装 Playwright

编写普通 Node.js 脚本时,先安装 Playwright 库和准备自动控制的浏览器:

$ mkdir website-screenshots-playwright
$ cd website-screenshots-playwright
$ npm init -y
$ npm i -D playwright
$ npx playwright install chromium

Playwright 库文档采用相同的基本流程:安装软件包、安装浏览器、导入 Playwright、启动浏览器,再与页面交互。以后需要 Firefox 或 WebKit 时,再安装相应浏览器。

为脚本和输出创建文件夹:

$ mkdir scripts screenshots

截取一个网站页面

创建 scripts/capture-one.js

const { chromium } = require("playwright");
const fs = require("node:fs/promises");

const url = "https://www.shotomatic.com/features";
const outputPath = "screenshots/shotomatic-features.png";

(async () => {
  await fs.mkdir("screenshots", { recursive: true });

  const browser = await chromium.launch();
  const context = await browser.newContext({
    viewport: { width: 1440, height: 1000 },
    deviceScaleFactor: 1,
  });

  const page = await context.newPage();

  try {
    await page.goto(url, { waitUntil: "load", timeout: 45_000 });
    await page.screenshot({ path: outputPath });
    console.log(`Saved ${outputPath}`);
  } finally {
    await context.close();
    await browser.close();
  }
})();

运行脚本:

$ node scripts/capture-one.js

这会截取可见视口。Playwright 的截图 API还支持整页截图、元素截图、缓冲区、裁剪和图片质量选项。

运行后会生成 screenshots/shotomatic-features.png

Playwright capture-one 示例输出的 Shotomatic 功能页截图
上述脚本输出的功能页,视口尺寸为 1440 × 1000。

截取整页截图

要截取整页截图,请传入 fullPage: true

await page.screenshot({
  path: "screenshots/shotomatic-features-full-page.png",
  fullPage: true,
});

需要从上到下保存整个文档时,用整页截图;关心访客在特定屏幕尺寸下看到什么时,用视口截图

Playwright 输出的 Shotomatic 功能页整页截图
同一 `/features` 页面在首屏以下区块完成渲染后的整页输出。

整页截图仍然取决于页面状态。fullPage: true 只会改变截图区域,不会强制渲染懒加载图片、动画或进入视口才出现的区块。下文的懒加载部分会说明页面状态为什么重要。

把目标 URL 放进批量脚本

单页脚本正常工作后,把目标 URL 移到可以接收列表、并用可预测文件名保存结果的脚本中。示例仍然只用 /features,便于查看输出。之后可以向同一数组添加更多 URL。

创建 scripts/capture-batch.js

const { chromium } = require("playwright");
const fs = require("node:fs/promises");

const urls = ["https://www.shotomatic.com/features"];

const outputDir = "screenshots";

function filenameForUrl(url, index) {
  const parsed = new URL(url);
  const rawName = `${parsed.hostname}${parsed.pathname}`;

  const slug = rawName
    .replace(/^www\./, "")
    .replace(/\/$/, "")
    .replace(/[^a-z0-9]+/gi, "-")
    .replace(/^-+|-+$/g, "")
    .toLowerCase();

  return `${String(index + 1).padStart(2, "0")}-${slug || "home"}.png`;
}

async function captureUrl(browser, url, index) {
  const context = await browser.newContext({
    viewport: { width: 1440, height: 1000 },
    deviceScaleFactor: 1,
  });

  const page = await context.newPage();
  const outputPath = `${outputDir}/${filenameForUrl(url, index)}`;

  try {
    await page.goto(url, { waitUntil: "load", timeout: 45_000 });
    await page.locator("body").waitFor({ state: "visible", timeout: 15_000 });
    await page.screenshot({ path: outputPath, fullPage: true });

    console.log(`Captured ${url} -> ${outputPath}`);
    return { url, ok: true, outputPath };
  } catch (error) {
    console.error(`Failed ${url}: ${error.message}`);
    return { url, ok: false, error: error.message };
  } finally {
    await context.close();
  }
}

(async () => {
  await fs.mkdir(outputDir, { recursive: true });

  const browser = await chromium.launch();

  try {
    const results = [];

    for (const [index, url] of urls.entries()) {
      results.push(await captureUrl(browser, url, index));
    }

    const failed = results.filter((result) => !result.ok);

    if (failed.length > 0) {
      process.exitCode = 1;
      console.error(`${failed.length} screenshot(s) failed.`);
    }
  } finally {
    await browser.close();
  }
})();

这个版本有意按顺序运行。速度较慢,但更容易调试。确认它能在你的页面上稳定工作后,再加入并发。

为较大批次加入并发

处理 5 个 URL 时,简单循环已经够用。处理 50 或 500 个 URL 时,通常需要一个较小的并发上限。

不要一次打开几百个页面。浏览器自动化很占内存,请求过于密集时,许多网站也会限流或出错。先从 2–4 个并发截图开始,确认结果稳定后再增加。

加入本指南 Puppeteer 版本所用的同一个辅助函数:

async function runWithConcurrency(items, limit, worker) {
  const results = new Array(items.length);
  let nextIndex = 0;

  async function runNext() {
    while (nextIndex < items.length) {
      const currentIndex = nextIndex;
      nextIndex += 1;
      results[currentIndex] = await worker(items[currentIndex], currentIndex);
    }
  }

  const workers = Array.from(
    { length: Math.min(limit, items.length) },
    () => runNext(),
  );

  await Promise.all(workers);
  return results;
}

然后替换原来的顺序循环:

const results = await runWithConcurrency(urls, 3, (url, index) =>
  captureUrl(browser, url, index),
);

这样可以复用一个浏览器,为每次截图创建相互隔离的浏览器上下文,并限制同时处于活动状态的页面数量。Playwright 库文档在 Node 脚本流程中也明确使用浏览器上下文,让每次截图拥有独立的生命周期。

截取手机或平板电脑页面

Playwright 提供常见手机和平板电脑的设备模拟描述符。例如:

const { chromium, devices } = require("playwright");

(async () => {
  const browser = await chromium.launch();
  const iPhone = devices["iPhone 13"];

  const context = await browser.newContext({
    ...iPhone,
  });

  const page = await context.newPage();
  await page.goto("https://www.shotomatic.com/features", {
    waitUntil: "load",
  });
  await page.screenshot({
    path: "screenshots/shotomatic-features-iphone-13.png",
  });

  await context.close();
  await browser.close();
})();

下面是用 iPhone 13 描述符截取的同一功能页:

Playwright 输出的 Shotomatic 功能页移动端视口截图
Playwright 使用 iPhone 13 设备描述符得到的移动端视口输出。

如果用户代理、触控支持、视口和设备像素比都很重要,请用设备描述符。只需要特定尺寸时,使用普通视口即可:

const context = await browser.newContext({
  viewport: { width: 390, height: 844 },
  deviceScaleFactor: 2,
  isMobile: true,
});

处理懒加载内容

许多页面只有在图片或区块进入视口后才会加载或显示。整页截图过早时,首屏以下还没有出现的内容会在截图中留下空白。

懒加载区块渲染前,Playwright 整页截图中出现大块空白
立即截图:页面高度正确,但部分内容尚未渲染。
滚动经过懒加载区块后得到的 Playwright 整页截图
滚动后截图:首屏以下的区块已有机会显示。

截取整页前,先滚动浏览文档,触发懒加载图片和进入视口才显示的区块:

async function triggerLazyLoading(page) {
  await page.evaluate(async () => {
    const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    const viewportHeight = window.innerHeight;
    const scrollHeight = document.body.scrollHeight;

    for (let y = 0; y < scrollHeight; y += viewportHeight) {
      window.scrollTo(0, y);
      await delay(600);
    }

    window.scrollTo(0, 0);
    await delay(300);
  });
}

page.screenshot() 前调用:

await page.goto(url, { waitUntil: "load", timeout: 45_000 });
await triggerLazyLoading(page);
await page
  .waitForFunction(
    () =>
      Array.from(document.images).every(
        (image) => image.complete && image.naturalWidth > 0,
      ),
    null,
    { timeout: 15_000 },
  )
  .catch(() => {});
await page.screenshot({ path: outputPath, fullPage: true });

有些页面还需要额外处理。自定义滚动容器、动画、延迟的 API 调用和虚拟化内容,都可能需要页面专用的选择器或状态判断。

选择合适的等待策略

大多数截图可靠性问题都与时机有关。

Playwright 的导航文档说明,page.goto() 默认等待 load 事件,但现代网页可能在该事件之后继续获取数据或渲染。截图时通常要采用以下策略之一:

  • 普通公开页面可以先从 waitUntil: "load" 开始;
  • 等待一个特定定位器,以证明所需内容已经渲染;
  • 就绪条件取决于应用状态时,使用 page.waitForFunction()
  • 图片采用懒加载时,截图前先滚动;
  • 不要把固定延时作为主要等待规则。

例如:

await page.goto(url, { waitUntil: "load", timeout: 45_000 });
await page
  .getByRole("heading", { name: "Shotomatic Features" })
  .waitFor({ state: "visible", timeout: 15_000 });
await page.screenshot({ path: outputPath, fullPage: true });

不要假设一种等待规则适用于所有页面。如果目标网站由你维护,等待定位器或应用状态通常比等待通用网络条件更可靠。

加入重试

网络请求会失败,页面会超时,第三方小组件也会卡住。真正用于批量任务的脚本,在放弃整次任务前,应该先重试失败的 URL。

async function withRetries(task, retries = 2) {
  let lastError;

  for (let attempt = 0; attempt <= retries; attempt += 1) {
    try {
      return await task();
    } catch (error) {
      lastError = error;
      console.warn(`Attempt ${attempt + 1} failed: ${error.message}`);
    }
  }

  throw lastError;
}

用它包裹页面操作:

await withRetries(async () => {
  await page.goto(url, { waitUntil: "load", timeout: 45_000 });
  await page.screenshot({ path: outputPath, fullPage: true });
});

在生产环境中,还应写入一份 JSON 报告,记录每个 URL、输出路径、状态、错误消息和时间戳。以后有人询问哪些页面失败、为什么失败时,这份报告能省下不少时间。

实用的文件夹结构

准备重复运行的截图任务,应把输入、输出和脚本分开保存:

website-screenshots-playwright/
  scripts/
    capture-batch.js
  urls/
    launch-pages.txt
    competitor-pages.txt
  screenshots/
    2026-06-23-launch/
    2026-06-23-competitors/
  reports/
    2026-06-23-launch.json

这样更容易重新运行工作流,也能让截图集与生成它的 URL 列表保持关联。

常见错误

  • **截图过早:**浏览器可能在所需内容可见之前就触发 load。请等待选择器,或加入页面专用检查。
  • **一次打开太多页面:**高并发可能导致浏览器崩溃、耗尽内存或触发限流。请从较小的数值开始。
  • **所有网站共用一种文件名模式:**URL 可能带有查询字符串、末尾斜杠、重复项和特殊字符。请始终清理文件名并加入索引。
  • **忘记清理浏览器资源:**关闭页面、上下文和浏览器。上下文泄漏会在长时间任务中成为实际问题。
  • **把整页截图当成视觉测试:**截图文件只是证据。视觉回归测试还需要基线、比较阈值和评审流程。

Playwright 截图脚本的替代方式

Playwright 不是自动截取网站截图的唯一方式。选择取决于第一版脚本完成后由谁负责这项工作。

如果只需要一段用途明确的浏览器自动化脚本,Puppeteer可能已经够用。截图属于更大的测试套件、需要覆盖 Chromium、Firefox 和 WebKit,或者已经在使用 Playwright Test 的运行器、跟踪与报告时,Playwright 更合适。

如果要把截图功能集成进产品,与自行维护浏览器相比,截图 API可能更省事。

如果不想编写和维护这个脚本,请阅读如何无代码自动截取网页。如果要从 URL 列表批量截图、为每个页面设置截图选项、检查结果并导出文件,又不想维护 Playwright 代码,可以使用 Shotomatic 的 Website Capture

常见问题

Playwright 可以自动截取网站截图吗?

可以。Playwright 能启动浏览器、打开 URL、设置视口或设备选项,并通过 page.screenshot() 保存页面截图。

Playwright 可以截取整页截图吗?

可以。向 page.screenshot() 传入 fullPage: true,即可截取整个可滚动页面,而不只是可见视口。

可以用 Playwright 截取多个 URL 吗?

可以。把 URL 放进数组,通过循环逐个处理,并为每次截图创建新的浏览器上下文。批次较大时,还要增加并发限制和错误处理。

网站截图应该用 Playwright 还是 Puppeteer?

需要跨浏览器覆盖、设备模拟,或要让截图成为较大测试工作流的一部分时,用 Playwright。脚本主要针对 Chrome 时,Puppeteer 也很实用。

什么时候无代码截图工作流比 Playwright 更合适?

如果需要由非开发人员运行、检查或导出 URL 列表截图,而且不想维护脚本、浏览器依赖和 CI 任务,无代码工作流更合适。

参考资料

以上示例已根据当前官方文档核对:

相关文章

查看更多文章

如何用 Puppeteer 自动截取网站截图

使用 Puppeteer 和 JavaScript 自动截取网站截图。通过可重复使用的脚本截取单页、整页、URL 批次和移动端视口。

约 18 分钟阅读
笔记本电脑上显示 Puppeteer 网站截图脚本代码

如何不写代码自动截取网站截图

选择无需代码的网站截图自动化方式:URL 列表截图、自动化平台配合截图 API、监控工具或浏览器辅助工具。

约 12 分钟阅读
用于检查网站截图工作流的桌面多显示器

如何在 Mac 上批量截取网站页面

用 Shotomatic 在 Mac 上批量截取网站:粘贴 URL 列表,选择桌面、平板或手机预设,并行截图,再导出用于审计或报告。

约 11 分钟阅读
多台笔记本电脑屏幕显示数字工作区

无需编写代码,自动截取网页

Website Capture 可以截取 URL 列表,为每个页面设置选项,检查结果并导出,不需要维护脚本。

如何用 Playwright 自动截取网站截图 | 博客 | Shotomatic