通过maven导入的jar包,1.1.5及之前的版本,都存在linux上杀不死chrome的bug,可以通过 1.1.5版本之前的内存问题解决方案 自行解决,仓库的代码已经将解决方案代码加上了,拉取下来打jar也可以用。
本库的灵感来自 Puppeteer(Node.js), API 也与其基本上保持一致,做这个库是为了方便使用 Java 操控 用于测试的Chrome (即Chrome for Testing,下面简称 Chrome)或 Chromium
Jvppeteer 通过 DevTools 控制 Chromium 或 Chrome。 默认情况下,以 headless (无界面)模式运行,也可以通过配置运行'有界面'模式。
你可以在浏览器中手动执行的绝大多数操作都可以使用 Jvppeteer 来完成! 下面是一些示例:
- 生成页面 PDF。
- 抓取 SPA(单页应用)并生成预渲染内容(即“SSR”(服务器端渲染))。
- 自动提交表单,进行 UI 测试,键盘输入等。
- 创建一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的 Chrome 中执行测试。
- 捕获网站的 timeline trace,用来帮助分析性能问题。
- 测试浏览器扩展。
要使用 maven,请将此依赖添加到pom.xml文件中:
<dependency>
<groupId>io.github.fanyong920</groupId>
<artifactId>jvppeteer</artifactId>
<version>2.2.5<version>
</dependency>
要使用 Gradle,请将 Maven 中央存储库添加到您的存储库列表中:
mavenCentral()
然后,您可以将最新版本添加到您的构建中。
compile "io.github.fanyong920:jvppeteer:2.2.5"
该库使用 SLF4J 进行日志记录,并且不附带任何默认日志记录实现。
调试程序将日志级别设置为 TRACE。
如果您不使用任何依赖项管理工具,则可以在此处找到最新的独立 jar 。
从2.0.0版本开始,Jvppeteer与 Chrome 配合使用, Chrome 使用的是新的无头模式,旧的无头模式现在是一个名为 chrome-headless-shell 的独立程序。无论你使用 Chrome 还是 chrome-headless-shell ,你只要将 headless 设置为 true, Jvppeteer 会自动匹配新的无头模式和旧的无头模式.
在此版本之前,Jvppeteer 下载并与 Chromium 配合使用。
下面是使用 Jvppeteer 下载浏览器的一些例子:
//采用默认配置下载浏览器,默认采用Chrome for Testing 浏览器。版本号Constant#Version
RevisionInfo revisionInfo = Puppeteer.downloadBrowser();
System.out.println("revisionInfo: " + revisionInfo);
//下载指定版本的chrome for Testing浏览器
RevisionInfo revisionInfo2 = Puppeteer.downloadBrowser("128.0.6613.137");
System.out.println("revisionInfo2: " + revisionInfo2);
//下载指定版本的ChromeDriver
FetcherOptions fetcherOptions = new FetcherOptions();
fetcherOptions.setProduct(Product.CHROMEDRIVER);
fetcherOptions.setVersion("129.0.6668.100");
RevisionInfo revisionInfo3 = Puppeteer.downloadBrowser(fetcherOptions);
System.out.println("revisionInfo3: " + revisionInfo3);
//下载指定版本的Chrome Headless Shell
FetcherOptions fetcherOptions2 = new FetcherOptions();
fetcherOptions2.setProduct(Product.CHROMEHEADLESSSHELL);
fetcherOptions2.setVersion("129.0.6668.100");
RevisionInfo revisionInfo4 = Puppeteer.downloadBrowser(fetcherOptions2);
System.out.println("revisionInfo4: " + revisionInfo4);
//下载指定版本的CHROMIUM
FetcherOptions fetcherOptions3 = new FetcherOptions();
fetcherOptions3.setProduct(Product.CHROMIUM);
fetcherOptions3.setVersion("1366415");
RevisionInfo revisionInfo5 = Puppeteer.downloadBrowser(fetcherOptions3);
System.out.println("revisionInfo5: " + revisionInfo5);
Jvpeteer 提供 Chrome、Chromium、ChromeDriver、Chrome Headless Shell 四种浏览器的下载功能。
下载 Chromium、ChromeDriver、Chrome Headless Shell 必须明确下载版本,Chrome 有默认版本,存放在Constant#VERSION 中。
关于下载浏览器的版本选择,可以浏览一下这两个网页:Chrome for Testing availability 与 JSON API endpoints
Mac必须withExcutablePath是用來指定启动Chrome.exe的路径。在Mac下载浏览器有问题。
每个 Jvppeteer 版本都有一个绑定的浏览器版本,最好采用绑定的浏览器版本使用 Jvppeteer。
下表提供了 Jvppeteer 版本与绑定的浏览器版本之间的映射。如果没有列出完全匹配的 Jvppeteer 版本,则支持的浏览器版本是紧接在前的版本:
2.2.0--2.2.5 | Chrome for Testing 130.0.6723.58 |
---|---|
2.1.2 | Chrome for Testing 128.0.6613.137 |
2.1.1 | Chrome for Testing 128.0.6613.137 |
2.1.0 | Chrome for Testing 128.0.6613.137 |
2.0.0 | Chrome for Testing 128.0.6613.137 |
1.1.6 | Chromium 722234 |
1.1.5 | Chromium 722234 |
1.1.4 | Chromium 722234 |
1.1.3 | Chromium 722234 |
1.1.2 | Chromium 722234 |
下载浏览器之后,我们就可以使用它与 Jvppeter 一起工作了,首先启动浏览器。
Puppeteer.launch();
//或者
Puppeteer.launch(launchOptions);
可以采用默认的配置启动浏览器,默认是无界面模式的,也可以添加可选配置 options 启动浏览器。
使用浏览器后,必须关闭它,使用 Browser.close() 关闭。
Browser browser = Puppeteer.launch();
Page page = browser.newPage();
browser.close();
如果你需要隔离自动化任务,请使用 BrowserContexts。Cookie 和本地存储不在浏览器上下文之间共享。
Browser browser = Puppeteer.launch(launchOptions);
BrowserContext defaultBrowserContext = browser.defaultBrowserContext();
Page page = defaultBrowserContext.newPage();
new Thread(() -> {
try {
page.evaluate("() => window.open('https://www.example.com/')");
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}).start();
Target target1 = defaultBrowserContext.waitForTarget(target -> target.url().equals("https://www.example.com/"));
System.out.println("target1:" + target1.url());
List<Page> pages = defaultBrowserContext.pages();
System.out.println("size1:" + pages.size());
defaultBrowserContext.newPage();
System.out.println("size2:" + defaultBrowserContext.pages().size());
List<Target> targets = defaultBrowserContext.targets();
for (Target target : targets) {
System.out.println("all target forEach:(" + target.type() + ":" + target.url() + ")");
}
BrowserContext browserContext = browser.createBrowserContext();
Page page1 = browserContext.newPage();
Browser browser1 = browserContext.browser();
System.out.println("broswer equals:" + (browser1 == browser));
browserContext.overridePermissions("https://www.baidu.com", WebPermission.GEOLOCATION);
page1.goTo("https://www.baidu.com");
browserContext.close();
System.out.println("close: " + browserContext.closed());
//默认浏览器不能关闭
defaultBrowserContext.close();
Thread.sleep(15000);
browser.close();
在浏览器上下文中,你可以打开一个新的页面,可以获得浏览器上下文的所有页面,可以通过关闭 浏览器上下文 来关闭 对应的所有页面,也可以给浏览器上下文授予独特的权限。**提醒 :创建多个浏览器上下文比创建多个浏览器好 **
如果你在 Jvppeteer 之外打开了一个新的浏览器,你可以用 Puppeteer.connect() 方法连接,连接远程的浏览器需要 URL,该 URL 可以是 Websocket URL(格式是 ws://HOST:PORT/devtools/browser/),也可以是 Browser URL (格式是 http://HOST:PORT )。
在 Browser URL 中的 PORT 是 debuggingPort,在浏览器启动时候加上参数:-remote-debugging-port=xxxx,debuggingPort 即 xxxx。
Browser URL 后加上 /json/version,格式是:http://HOST:PORT/json/version 可以获取到 WebSocket URL
String wsEndpoint = browser.wsEndpoint();
browser.disconnect();
//ws连接
Browser wsBrowser = Puppeteer.connect(wsEndpoint);
wsBrowser.disconnect();
//url连接 http://host:port 因为启动时候配置DebuggingPort=9222 所以url = localhost:9222
Browser urlBrowser = Puppeteer.connect("http://localhost:9222");
要打印 PDF,请使用 Page.pdf() 。手动在浏览器按Ctrl+P可以预览 PDF,弹出的窗口就是 PDF 样式,把各个选项点一下,看一下预览效果 然后再回来写代码。
//pdf必须配置headless = true
launchOptions.setHeadless(true);
ArrayList<String> args = new ArrayList<>();//添加一些额外的启动参数
args.add("--no-sandbox");//pdf必须添加这个参数,不然无法打印,具体看这里https://github.com/puppeteer/puppeteer/issues/12470
launchOptions.setArgs(args);
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
GoToOptions goToOptions = new GoToOptions();
goToOptions.setWaitUntil(Collections.singletonList(PuppeteerLifeCycle.NETWORKIDLE));
page.goTo("https://www.baidu.com/?tn=68018901_16_pg",goToOptions);
PDFOptions pdfOptions = new PDFOptions();
pdfOptions.setPath("baidu.pdf");
pdfOptions.setOutline(true);//生成大纲
pdfOptions.setFormat(PaperFormats.a4);//A4大小
pdfOptions.setPrintBackground(true);//打印背景图形,百度一下这个蓝色按钮就显示出来了
pdfOptions.setPreferCSSPageSize(false);
pdfOptions.setScale(1.1);//缩放比例1.1
page.pdf(pdfOptions);
//关闭浏览器
browser.close();
默认情况下,Page.pdf() 等待字体加载。
要捕获屏幕截图,请使用 Page.screenshot()。
@Test
public void test3() throws Exception {
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.baidu.com/?tn=68018901_16_pg");
ScreenshotOptions screenshotOptions = new ScreenshotOptions();
screenshotOptions.setPath("baidu.png");
screenshotOptions.setOmitBackground(true);
//全屏截图
screenshotOptions.setFullPage(true);
//截图的更多
screenshotOptions.setCaptureBeyondViewport(true);
page.screenshot(screenshotOptions);
browser.close();
}
@Test
public void test4() throws Exception {
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.baidu.com/?tn=68018901_16_pg");
ScreenshotOptions screenshotOptions = new ScreenshotOptions();
screenshotOptions.setPath("baidu.png");
//指定图片类型,path指定的名称中的后缀便不起作用了
screenshotOptions.setType(ImageType.JPEG);
//jpg可以设置这个选项
screenshotOptions.setQuality(80.00);
//全屏截图
screenshotOptions.setFullPage(true);
page.screenshot(screenshotOptions);
browser.close();
}
@Test
public void test5() throws Exception {
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.baidu.com/?tn=68018901_16_pg");
ScreenshotOptions screenshotOptions = new ScreenshotOptions();
screenshotOptions.setPath("baidu.jpeg");
//指定图片类型,path指定的名称中的后缀便不起作用了
screenshotOptions.setType(ImageType.WEBP);
//jpg可以设置这个选项
screenshotOptions.setQuality(80.00);
//全屏截图
screenshotOptions.setFullPage(true);
page.screenshot(screenshotOptions);
browser.close();
}
要捕录制屏幕,请使用 Page.screencast()。
/**
* 录制屏幕某个区域 录制格式webm
*/
@Test
public void test25() throws IOException {
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.geetest.com/demo/slide-en.html");
ScreencastOptions screencastOptions = new ScreencastOptions();
screencastOptions.setPath("D:\\test\\test2.webm");
screencastOptions.setFormat(ScreenCastFormat.WEBM);
//指定ffmpeg路径,如果配置了系统的环境变量,那么可以不指定
BoundingBox boundingBox = page.$("#username").boundingBox();
screencastOptions.setCrop(boundingBox);
screencastOptions.setFfmpegPath("D:\\windowsUtil\\ffmpeg.exe");
ScreenRecorder screencast = page.screencast(screencastOptions);
page.type("#username", "123456789", 200);
page.type("#password", "123456789", 200);
screencast.stop();
browser.close();
}
/**
* 录制屏幕 录制格式gif
*/
@Test
public void test26() throws IOException {
Browser browser = Puppeteer.launch(launchOptions);
Page page = browser.newPage();
page.goTo("https://www.geetest.com/demo/slide-en.html");
ScreencastOptions screencastOptions = new ScreencastOptions();
screencastOptions.setPath("D:\\test\\test.gif");
screencastOptions.setFormat(ScreenCastFormat.GIF);
screencastOptions.setFfmpegPath("D:\\windowsUtil\\ffmpeg.exe");
ScreenRecorder screencast = page.screencast(screencastOptions);
page.type("#username", "123456789", 200);
page.type("#password", "123456789", 200);
screencast.stop();
browser.close();
}
更多的例子请看项目内的example文件夹 点击这里,是入门级别的例子,对如何使用 Jvppeteer 有很大帮助。
如果你在 Linux 上安装 Chrome 并运行 遇到麻烦,或者在某个场景中遇到麻烦,可以 在 Puppeteer(Node.js) 库中的 Troubleshooting 寻找答案,也可以在其 issues 中寻找一些解决问题的思路,或者google baidu puppeteer的解决方案,再应用到你的问题上。
在 dev21分支 上使用了 jdk21 进行了部分代码修改,主要在 Connection 类上使用了虚拟线程处理消息,有兴趣可以自己打 JAR 包试试。
- Puppeteer中文文档 : 更加详细的 API 文档 ,多看看了解一下
- DevTools Protocol :CDP 协议
- Chrome命令行启动参数
此仓库中找到的所有内容均已获得 Apache 许可。有关详细信息,请参见LICENSE
文件