java利用phantomjs进行截图实例教程
前言
最近工作中遇到一个需求,需要实现截图功能,断断续续查找资料、验证不同的实现方法终于算基本搞定了页面截图,因为中间过程曲折花费较多时间,分享出来帮助大家快速实现截图
为什么选用phantomjs进行截图
截图可以实现的方式有很多,比如:
- selenium
- htmlunit
- html2image、、、and so on但是这些实现的截图效果都不好。selenium只能实现截屏,不能截取整个页面,而htmlunit、html2image对js的支持效果并不好,截下来的图会有很多空白。phantomjs就是万精油了,既能截取整个页面,对js支持的效果又好
plantomjs提供了如 css 选择器、dom操作、json、html5、canvas、svg 等。phantomjs 的用处很广泛,如网络监控、网页截屏、页面访问自动化、无需浏览器的 web 测试等,这里只用到网页截屏。
前期准备
安装phantomjs。mac os
brew install phantomjs
命令行的方式进行截图
安装以后我们就可以小试牛刀了
打开终端,输入以下命令:
/users/hetiantian/softwares/phantomjs/bin/phantomjs /users/hetiantian/softwares/phantomjs/examples/rasterize.js https://juejin.im/post/5bb24bafe51d450e4437fd96 /users/hetiantian/desktop/juejin-command.png
查看效果
发现图片没有加载好
来看以下刚刚的命令行:
/users/hetiantian/softwares/phantomjs/bin/phantomjs:phantomjs可执行文件保存地址
/users/hetiantian/softwares/phantomjs/examples/rasterize.js:rasterize.js文件地址
这段命令可以理解为用phantomjs去运行rasterize.js文件,所以要想解决图片空白的问题我们需要去看一下rasterize.js文件。
"use strict"; var page = require('webpage').create(), system = require('system'), address, output, size, pagewidth, pageheight; if (system.args.length < 3 || system.args.length > 5) { console.log('usage: rasterize.js url filename [paperwidth*paperheight|paperformat] [zoom]'); console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "a4", "letter"'); console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px'); console.log(' "800px*600px" window, clipped to 800x600'); phantom.exit(1); } else { address = system.args[1]; output = system.args[2]; page.viewportsize = { width: 600, height: 600 }; if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") { size = system.args[3].split('*'); page.papersize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } : { format: system.args[3], orientation: 'portrait', margin: '1cm' }; } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") { size = system.args[3].split('*'); if (size.length === 2) { pagewidth = parseint(size[0], 10); pageheight = parseint(size[1], 10); page.viewportsize = { width: pagewidth, height: pageheight }; page.cliprect = { top: 0, left: 0, width: pagewidth, height: pageheight }; } else { console.log("size:", system.args[3]); pagewidth = parseint(system.args[3], 10); pageheight = parseint(pagewidth * 3/4, 10); // it's as good an assumption as any console.log ("pageheight:",pageheight); page.viewportsize = { width: pagewidth, height: pageheight }; } } if (system.args.length > 4) { page.zoomfactor = system.args[4]; } page.open(address, function (status) { if (status !== 'success') { console.log('unable to load the address!'); phantom.exit(1); } else { window.settimeout(function () { page.render(output); phantom.exit(); }, 200); } }); }
尝试一:
对page.viewportsize = { width: 600, height: 600 };产生了疑问????️
把height调大十倍,发现基本是完美截图了,但是如果页面的篇幅特别短,会发现有瑕疵,下面留有一大片空白。原因:page.viewportsize = { width: 600, height: 600 };设置的是初始打开浏览器的大小,通过增大这个值可以加载js。如果我们能拿到实际页面的大小在设置height大小,但是不,我不能。
并且不能接受预先设定一个很大的height值,比如30000,因为不能接受底下留白的效果
尝试二:
在window.settimeout方法之前加入以下代码
page.evaluate(function(){ scrollby(0, 18000); });
无奈evaluate里不能在用for循环了,前端渣渣真的不知道如何改,遂放弃
java代码方式进行截图
需要的依赖
<dependency> <groupid>org.seleniumhq.selenium</groupid> <artifactid>selenium-java</artifactid> <version>2.45.0</version> </dependency> <dependency> <groupid>com.codeborne</groupid> <artifactid>phantomjsdriver</artifactid> <version>1.2.1</version> <!-- this will _always_ be behind --> <exclusions> <exclusion> <groupid>org.seleniumhq.selenium</groupid> <artifactid>selenium-java</artifactid> </exclusion> <exclusion> <groupid>org.seleniumhq.selenium</groupid> <artifactid>selenium-remote-driver</artifactid> </exclusion> </exclusions> </dependency>
代码实现
public class phantomjstest2 { public static void main(string[] args) throws interruptedexception, ioexception { //设置必要参数 desiredcapabilities dcaps = new desiredcapabilities(); //ssl证书支持 dcaps.setcapability("acceptsslcerts", true); //截屏支持 dcaps.setcapability("takesscreenshot", true); //css搜索支持 dcaps.setcapability("cssselectorsenabled", true); //js支持 dcaps.setjavascriptenabled(true); //驱动支持(第二参数表明的是你的phantomjs引擎所在的路径) dcaps.setcapability(phantomjsdriverservice.phantomjs_executable_path_property, "/users/hetiantian/softwares/phantomjs/bin/phantomjs"); //创建*面浏览器对象 phantomjsdriver driver = new phantomjsdriver(dcaps); //设置隐性等待(作用于全局) driver.manage().timeouts().implicitlywait(1, timeunit.seconds); long start = system.currenttimemillis(); //打开页面 driver.get("https://juejin.im/post/5bb24bafe51d450e4437fd96"); thread.sleep(30 * 1000); javascriptexecutor js = driver; for (int i = 0; i < 33; i++) { js.executescript("window.scrollby(0,1000)"); //睡眠10s等js加载完成 thread.sleep(5 * 1000); } //指定了outputtype.file做为参数传递给getscreenshotas()方法,其含义是将截取的屏幕以文件形式返回。 file srcfile = ((takesscreenshot)driver).getscreenshotas(outputtype.file); thread.sleep(3000); //利用fileutils工具类的copyfile()方法保存getscreenshotas()返回的文件对象 fileutils.copyfile(srcfile, new file("/users/hetiantian/desktop/juejin-01.png")); system.out.println("耗时:" + (system.currenttimemillis() - start) + " 毫秒"); } }
注释已经够详细了不多说了。唯一说一点:通过去执行js代码实现页面滑动,并且每次滑动都会通过睡眠保证有时间可以将 js加载进来。会调用33次滑动,因为phantomjs截取最大的高度为32767px(int 32位的最大整数),所以滑动33次可以保证能够截取到的最大页面部分其js已经是加载完成了的
附:window.scrollby(0,1000)、window.scrollto(0,1000)的区别
window.scrollby(0,1000)
window.scrollby(0,1000)
执行到这里页面滑动1000+1000px
window.scrollto(0,1000)
window.scrollto(0,1000)
执行到这里页面滑动到1000px处
window.scrollto(0, document.body.scrollheight可以滑动到页面底部,不选择有两个原因:
1)一下子滑动到底部js会来不及被加载
2)有些页面没有底部,可以一直滑动加载
注:这里所说的js来不及加载指的是:想要截取页面的js来不及加载
该方式的缺点:比较费时间。果然熊和鱼掌不可兼得也,统计了一下截取一张图片大概需要四分多钟
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
推荐阅读