You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Headless Chrome录制网站视频?求服务器端捕获CSS动画为MP4的方案

用Headless Chrome录制网站视频(含CSS动画转MP4)的实用方案

嘿,这个需求我太熟了!之前帮团队做过好几个CSS动画的服务器端录制任务,下面给你梳理几个靠谱的方案,从原生Headless Chrome+Puppeteer的手动实现,到更省心的工具都有:

一、用Puppeteer + FFmpeg手动合成视频

Puppeteer本身没有直接录视频的API,但我们可以通过捕获页面帧再合成视频的方式实现,特别适合精准控制CSS动画的录制时机:

核心步骤:

  1. 启动Headless Chrome并加载目标页面:确保CSS动画能自动播放(有些页面可能需要触发,或者设置prefers-reduced-motion让动画正常运行)
  2. 定时捕获页面截图:按照动画的帧率(比如30fps),每隔1000/30毫秒截取一帧
  3. 用FFmpeg将帧序列合成MP4:把所有截图按顺序拼接成流畅的视频

示例代码片段:

const puppeteer = require('puppeteer');
const fs = require('fs');
const { exec } = require('child_process');

(async () => {
  const browser = await puppeteer.launch({ headless: 'new' });
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 720 });
  // 确保CSS动画不被"减少动画"偏好禁用
  await page.emulateMediaFeatures([{ name: 'prefers-reduced-motion', value: 'no-preference' }]);
  
  await page.goto('你的目标页面URL');
  // 等待动画完全加载(比如等某个元素的动画类出现)
  await page.waitForSelector('.animated-element');

  // 创建临时目录存帧
  const frameDir = './temp-frames';
  if (!fs.existsSync(frameDir)) fs.mkdirSync(frameDir);

  // 捕获30秒的帧(30fps,共900帧)
  const fps = 30;
  const duration = 30;
  for (let i = 0; i < fps * duration; i++) {
    await page.screenshot({ path: `${frameDir}/frame-${i.toString().padStart(4, '0')}.png` });
    await new Promise(resolve => setTimeout(resolve, 1000/fps));
  }

  await browser.close();

  // 用FFmpeg合成MP4
  exec(`ffmpeg -r ${fps} -i ${frameDir}/frame-%04d.png -c:v libx264 -pix_fmt yuv420p output.mp4`, (err, stdout, stderr) => {
    if (err) {
      console.error(`合成失败: ${err}`);
      return;
    }
    console.log('视频合成完成!');
    // 可选:删除临时帧文件
    fs.rmSync(frameDir, { recursive: true });
  });
})();

注意点:

  • 帧率要和CSS动画的animation-durationanimation-iteration-count匹配,避免卡顿或快进
  • 如果动画是无限循环的,可以设置固定录制时长,或者监听动画结束事件再停止截图

二、更省心的服务器端工具推荐

如果不想手动拼帧,这些工具能帮你省不少事:

1. Playwright(强烈推荐)

作为Puppeteer的继任者,Playwright原生支持视频录制,不用依赖外部工具,代码极简,还支持Chrome、Firefox、Safari多浏览器:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({
    recordVideo: { dir: './recordings/' } // 自动录制视频到指定目录
  });
  const page = await context.newPage();
  await page.setViewport({ width: 1280, height: 720 });
  await page.emulateMediaFeatures([{ name: 'prefers-reduced-motion', value: 'no-preference' }]);
  
  await page.goto('你的目标页面URL');
  await page.waitForTimeout(30000); // 等待30秒动画完成
  // 或者监听动画结束事件:await page.waitForFunction('document.querySelector(".animated-element").getAnimations()[0].finished')

  await context.close();
  await browser.close();
  console.log('视频录制完成,已保存到./recordings/');
})();

Playwright会自动处理帧捕获和编码,生成的MP4质量很高,而且支持设置视频尺寸、帧率等参数,非常适合服务器端批量录制。

2. FFmpeg + Chrome DevTools Protocol(CDP)

如果不想用Node.js库,可以直接通过CDP控制Headless Chrome,同时用FFmpeg捕获Chrome的视频流。这种方式适合纯命令行环境:

# 启动Headless Chrome并开启CDP端口
google-chrome --headless=new --remote-debugging-port=9222 --window-size=1280,720 https://your-target-page.com &

# 用FFmpeg通过CDP捕获视频流
ffmpeg -f chrome -i http://localhost:9222 output.mp4

这个方案不需要写代码,直接用命令行就能完成,适合快速测试或脚本自动化。

3. Puppeteer-Recorder(第三方封装库)

这是一个专门为Puppeteer做的录制工具,封装了截图和FFmpeg合成的逻辑,API更简洁:

const PuppeteerRecorder = require('puppeteer-recorder');

(async () => {
  await PuppeteerRecorder.record({
    browser: 'chrome',
    url: '你的目标页面URL',
    viewport: { width: 1280, height: 720 },
    output: 'css-animation.mp4',
    fps: 30,
    duration: 30,
    emulateMediaFeatures: [{ name: 'prefers-reduced-motion', value: 'no-preference' }]
  });
})();

三、针对CSS动画的优化技巧

  • 禁用"减少动画"偏好:Headless Chrome默认可能会尊重prefers-reduced-motion,所以一定要用emulateMediaFeatures强制开启动画
  • 固定视口:录制前设置固定的视口大小,避免页面响应式变化影响录制效果
  • 关闭干扰元素:用page.$eval隐藏弹窗、广告等不需要的元素,确保动画是画面焦点
  • 预加载资源:用page.waitForLoadState('networkidle')等待页面资源完全加载后再开始录制,避免动画卡顿

内容的提问来源于stack exchange,提问作者Mikhail Novikov

火山引擎 最新活动