在线截图服务受配额、隐私和页面复杂度限制;用 Playwright 在本地或 CI 里跑同一套脚本,长页与批量 URL 可复现、可版本管理,是高热度网社区里更稳的「黑科技」实用工具路线。
在线截图工具的局限与本地自动化的适用场景
常见在线工具的问题
- 配额与限速:免费档每日次数有限,批量 URL 容易触顶。
- 隐私与合规:内网、登录态、含敏感数据的页面不宜上传到第三方。
- 页面还原差:懒加载、无限滚动、自定义字体、WebGL 常截不全或空白。
- 不可复现:同一 URL 不同时间结果不一致,难以做回归对比。
适合用 Playwright 本地/CI 的场景
| 场景 | 说明 |
|---|---|
| 文档/营销页归档 | 固定视口全页 PNG,入库或发 PR 附件 |
| 多环境对比 | staging / prod 同一脚本批量截,diff 视觉 |
| 移动端验收 | 切换 device 描述符,一次跑 iPhone/Android 视口 |
| 定时巡检 | cron 或 GitHub Actions nightly 截关键页面 |
自动化测试栈里 Playwright 本就是为「真实浏览器渲染」设计的,拿来做网页截图是顺手能力,不必再绑 Selenium 或 Puppeteer 若你已在用 Playwright 测 E2E。
Node 环境安装 Playwright 与最小可运行脚本
环境要求
- Node.js 18+(LTS 推荐)
- 磁盘空间:Chromium 浏览器包约 150MB+
安装步骤
mkdir playwright-screenshots && cd playwright-screenshots
npm init -y
npm install playwright
npx playwright install chromium
只装 Chromium 可减小体积;需要 WebKit/Firefox 时再 npx playwright install。
最小可运行脚本
新建 screenshot.js:
const { chromium } = require('playwright');
const path = require('path');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.screenshot({ path: 'example.png', fullPage: true });
await browser.close();
console.log('saved example.png');
})();
运行:
node screenshot.js
常见安装坑
playwright install未执行:运行时报找不到 browser,务必在项目里执行npx playwright install chromium。- 公司代理:设置
HTTPS_PROXY/HTTP_PROXY后再 install。 - Linux 无头依赖:CI 里若缺库,用 Playwright 官方 Docker 镜像或
npx playwright install-deps(需 sudo)。
长页面全屏截图、移动端视口与批量 URL 配置
长页面全屏截图
fullPage: true 会滚动并拼接整页;注意:
await page.goto(url, {
waitUntil: 'networkidle', // 或 'domcontentloaded' 加快,但可能截到未加载图
timeout: 60000,
});
// 懒加载:滚到底再截
await page.evaluate(async () => {
await new Promise((resolve) => {
let total = 0;
const distance = 400;
const timer = setInterval(() => {
window.scrollBy(0, distance);
total += distance;
if (total >= document.body.scrollHeight) {
clearInterval(timer);
window.scrollTo(0, 0);
resolve();
}
}, 100);
});
});
await page.screenshot({
path: outPath,
fullPage: true,
type: 'png',
});
- 超大页内存:极高页面可能 OOM,可改用
clip分段截再拼接,或限制最大高度。 deviceScaleFactor:Retina 清晰图可page.setViewportSize({ width: 1280, height: 720 });并设deviceScaleFactor: 2(在newContext时)。
移动端视口
用内置设备描述符,比手调 UA 更稳:
const { devices } = require('playwright');
const iPhone = devices['iPhone 13'];
const context = await browser.newContext({
...iPhone,
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({ path: 'mobile.png', fullPage: true });
await context.close();
常用:iPhone 13、Pixel 5、Galaxy S9+。高热度网博客做响应式验收时,同一 URL 循环多种 devices 即可。
批量 URL 配置
推荐 urls.json + 循环,失败单条不拖死整批:
const fs = require('fs');
const { chromium } = require('playwright');
const urls = JSON.parse(fs.readFileSync('urls.json', 'utf8'));
// urls.json: [ { "url": "https://a.com", "name": "home" }, ... ]
(async () => {
const browser = await chromium.launch({ headless: true });
const outDir = path.join(__dirname, 'output');
fs.mkdirSync(outDir, { recursive: true });
for (const item of urls) {
const page = await browser.newPage();
try {
await page.goto(item.url, { waitUntil: 'networkidle', timeout: 90000 });
const file = path.join(outDir, `${item.name || 'shot'}.png`);
await page.screenshot({ path: file, fullPage: true });
console.log('OK', item.url);
} catch (e) {
console.error('FAIL', item.url, e.message);
} finally {
await page.close();
}
}
await browser.close();
})();
- 并发:默认串行最稳;要快可用
p-limit限制 3–5 并发,避免内存暴涨。 - 文件名:用
name或 URL hash,避免非法字符。
定时任务与 GitHub Actions 集成时的路径、权限与失败重试
本地定时任务(cron)
# 每天 2 点,日志追加
0 2 * * * cd /path/to/playwright-screenshots && /usr/bin/node batch.js >> /var/log/playwright-shot.log 2>&1
- 使用绝对路径的
node(which node)。 - 工作目录必须是项目根,否则相对路径
output/、urls.json会错。
GitHub Actions 要点
.github/workflows/screenshots.yml 示例骨架:
name: nightly-screenshots
on:
schedule:
- cron: '0 18 * * *' # UTC,按需要改
workflow_dispatch:
jobs:
shot:
runs-on: ubuntu-latest
permissions:
contents: write # 若要 commit 截图回仓库
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npx playwright install chromium --with-deps
- run: node batch.js
env:
CI: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: screenshots
path: output/
路径与权限
- Artifact 路径:与脚本里
output/一致; monorepo 时在working-directory下执行node scripts/batch.js。 contents: write:仅在你需要git add output && git commit时开启;公开仓注意勿提交含 token 的页面截图。- Secrets:登录态用
storageState从加密 secret 写入 JSON,勿写进仓库。
// 使用已保存登录态(本地生成一次 login.js 保存 state.json)
const context = await browser.newContext({
storageState: process.env.STORAGE_STATE_PATH || 'state.json',
});
失败重试
- 单 URL:简单重试 2–3 次,指数退避。
async function gotoWithRetry(page, url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
await page.goto(url, { waitUntil: 'networkidle', timeout: 90000 });
return;
} catch (e) {
if (i === retries - 1) throw e;
await new Promise((r) => setTimeout(r, 2000 * (i + 1)));
}
}
}
- Workflow 级:对 flaky 网络可
continue-on-error: true单步 + 汇总 job;或nick-fields/retry@v2包裹node batch.js。 - CI 稳定性:
launch({ headless: true })足够;避免依赖slowMo;超时比本地略大。
与自动化测试的关系
同一仓库可共用 @playwright/test 的配置与 globalSetup 登录;截图脚本保持独立 node batch.js 也可,减少测试报告耦合。Playwright 官方 trace 不必为纯截图开启。
小结:用 Node Playwright 做网页截图批处理,核心是 fullPage、视口/device、批量 JSON 与 CI 里 install --with-deps、artifact 路径一致。替代在线工具后,流程可进 Git、可重试,更适合高热度网这类追求可复现黑科技的日常实用工具流。
评论
填写昵称与邮箱即可评论,无需登录。