Java环境下无头模式Selenium测试录屏方案咨询
无头Chrome下Selenium测试录屏的可行方案
方案1:利用Chrome DevTools Protocol(CDP)原生录屏
无头Chrome支持通过CDP直接捕获页面帧,无需额外第三方工具,适合Java环境集成。
实现步骤:
- 初始化无头ChromeDriver时开启CDP会话
- 通过CDP的
Page.startScreencast命令启动录屏,配置帧率、分辨率等参数 - 监听
Page.screencastFrame事件接收帧数据 - 测试结束后停止录屏,将帧数据合成视频文件
Java代码示例:
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.devtools.DevTools; import org.openqa.selenium.devtools.v128.page.Page; import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Optional; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import com.xuggle.xuggler.IMediaWriter; import com.xuggle.xuggler.ToolFactory; import java.util.concurrent.TimeUnit; public class HeadlessRecording { public static void main(String[] args) throws Exception { // 配置无头Chrome ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); options.addArguments("--disable-gpu"); options.addArguments("--window-size=800,600"); ChromeDriver driver = new ChromeDriver(options); DevTools devTools = driver.getDevTools(); devTools.createSession(); // 启动录屏,设置10fps,800x600分辨率 devTools.send(Page.startScreencast( Optional.empty(), Optional.of(10), Optional.of(800), Optional.of(600), Optional.of(100) )); List<byte[]> videoFrames = new ArrayList<>(); // 监听帧数据,解码后存储 devTools.addListener(Page.screencastFrame(), frame -> { byte[] decodedFrame = Base64.getDecoder().decode(frame.getData()); videoFrames.add(decodedFrame); // 确认接收帧,避免CDP停止发送 devTools.send(Page.screencastFrameAck(frame.getSessionId())); }); // 执行测试逻辑 driver.get("https://example.com"); // 这里替换为你的测试步骤 Thread.sleep(3000); // 停止录屏 devTools.send(Page.stopScreencast()); // 用Xuggler合成MP4视频(需引入Xuggler依赖) IMediaWriter writer = ToolFactory.makeWriter("test-recording.mp4"); writer.addVideoStream(0, 0, com.xuggle.xuggler.ICodec.ID.CODEC_ID_MPEG4, 800, 600); long timestamp = 0; for (byte[] frameBytes : videoFrames) { BufferedImage frame = ImageIO.read(new ByteArrayInputStream(frameBytes)); writer.encodeVideo(0, frame, timestamp, TimeUnit.MILLISECONDS); timestamp += 100; // 对应10fps的时间间隔 } writer.close(); driver.quit(); } }
方案2:使用Monte Media Library录制虚拟显示(跨Windows/Linux)
如果需要录制整个虚拟桌面的内容(适合无法通过CDP捕获的场景),可以用Monte库结合虚拟显示工具:
- Linux:用Xvfb创建虚拟显示
- Windows:用VNC或系统自带的虚拟桌面
实现步骤:
- 启动虚拟显示(Linux下需提前启动Xvfb)
- 配置Chrome在虚拟显示中运行(Linux需设置
DISPLAY环境变量) - 用Monte启动屏幕录制
- 执行测试后停止录制,保存视频
Java代码示例(Monte):
import org.monte.media.Format; import org.monte.media.FormatKeys; import org.monte.media.Registry; import org.monte.media.math.Rational; import org.monte.screenrecorder.ScreenRecorder; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import java.awt.*; import java.io.File; import static org.monte.media.AudioFormatKeys.*; import static org.monte.media.VideoFormatKeys.*; public class MonteScreenRecording { public static void main(String[] args) throws Exception { // Linux下需先执行:Xvfb :1 -screen 0 800x600x24,然后设置环境变量 // System.setProperty("DISPLAY", ":1"); // 配置录制参数 GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice().getDefaultConfiguration(); ScreenRecorder recorder = new ScreenRecorder(gc, new Format(MediaTypeKey, FormatKeys.MediaType.FILE, MimeTypeKey, MIME_AVI), new Format(MediaTypeKey, FormatKeys.MediaType.VIDEO, EncodingKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE, CompressorNameKey, ENCODING_AVI_TECHSMITH_SCREEN_CAPTURE, DepthKey, 24, FrameRateKey, Rational.valueOf(15), QualityKey, 1.0f, KeyFrameIntervalKey, 15 * 60), new Format(MediaTypeKey, FormatKeys.MediaType.AUDIO, EncodingKey, "PCM", SampleRateKey, 44100, SampleSizeInBitsKey, 16, ChannelsKey, 2), null); recorder.start(); // 启动无头Chrome ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); options.addArguments("--window-size=800,600"); ChromeDriver driver = new ChromeDriver(options); driver.get("https://example.com"); // 执行测试步骤 Thread.sleep(3000); driver.quit(); recorder.stop(); // 录制的视频默认保存在用户目录下的Movies文件夹 File videoFile = recorder.getCreatedFiles().get(0); System.out.println("视频保存路径:" + videoFile.getAbsolutePath()); } }
方案3:FFmpeg Java绑定库直接编码帧
如果需要更高效的视频编码,可以用FFmpeg的Java绑定(比如ffmpeg-java)替代Xuggler,结合CDP获取的帧数据直接生成视频,性能和兼容性更好。
核心思路:
- 通过CDP获取Base64编码的帧数据
- 将帧数据解码为原始图像
- 用FFmpeg Java库将图像序列编码为MP4/WebM等格式
关键代码片段(结合CDP):
// 承接方案1的帧数据获取逻辑 // 引入ffmpeg-java依赖后,编码示例: FFmpeg.atPath() .addInput(FrameInput.create() .addFrame(videoFrames.stream() .map(frameBytes -> { try { return JavaFrameConverter.toFrame(ImageIO.read(new ByteArrayInputStream(frameBytes))); } catch (IOException e) { throw new RuntimeException(e); } }) .collect(Collectors.toList())) .setFrameRate(10)) .addOutput("test-recording.mp4") .setVideoCodec("libx264") .setPreset("ultrafast") .run();
内容的提问来源于stack exchange,提问作者Oriol Julià Torres
相关产品推荐
相关产品推荐

