断断续续查找资料、验证不同的实现方法终于算基本搞定了页面截图,因为中间过程曲折花费较多时间,分享出来帮助大家快速实现截图
截图可以实现的方式有很多,比如:
安装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循环了,前端渣渣真的不知道如何改,遂放弃
<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来不及加载 该方式的缺点:比较费时间。果然熊和鱼掌不可兼得也,统计了一下截取一张图片大概需要四分多钟