Java 实现通过网址URL截取整个网页的长图并保存(遇到的各种坑) |
您所在的位置:网站首页 › 浏览器打开网址截图骗局 › Java 实现通过网址URL截取整个网页的长图并保存(遇到的各种坑) |
1.寻找实现的技术
通过查询资料发现可以用 Selenium + PhantomJS 进行实现(通过浏览器模拟打开页面,并截图),通过查找资料实现了功能,发现通过PhantomJS截出来的图片变形严重。 通过Selenium 的官网 发现Selenium 是支持所有主流的浏览器驱动进行模拟浏览器,且官方不推荐PhantomJS。 Selenium是一个用于Web应用程序测试的工具 PhantomJS是一个基于webkit的JavaScript API 支持的浏览器如下: 不建议使用说明: 所以后面打算用Chome驱动结合去使用 2. 编码实现2.1环境准备 项目中导入对应的jar org.seleniumhq.selenium selenium-java 3.141.59 com.google.guava guava 27.0-jre 准备chome驱动 https://registry.npmmirror.com/binary.html?path=chromedriver/&spm=a2c6h.24755359.0.0.6d444dccLAiv2m 通过这个地址去下载对应版本的驱动 window 下载Windows的 Linux下载对应Linux的 我这里用的是 90.0.4430.24 这个版本 2.1开始编码 public static void guge(String url){ //这里设置下载的驱动路径,Windows对应chromedriver.exe Linux对应chromedriver,具体路径看你把驱动放在哪 System.setProperty("webdriver.chrome.driver", "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); //ssl证书支持 options.setCapability("acceptSslCerts", true); //截屏支持 options.setCapability("takesScreenshot", true); //css搜索支持 options.setCapability("cssSelectorsEnabled", true); options.setHeadless(true); ChromeDriver driver = new ChromeDriver(options); try { //设置需要访问的地址 driver.get(url); //获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高; Long width = (Long)driver.executeScript("return document.documentElement.scrollWidth"); Long height =(Long) driver.executeScript("return document.documentElement.scrollHeight"); System.out.println("高度:"+height); //设置窗口宽高,设置后才能截全 driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue())); //设置截图文件保存的路径 String screenshotPath = "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\img\\imgGG.png"; File srcFile = driver.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcFile, new File(screenshotPath)); }catch (Exception e){ throw new RuntimeException("截图失败",e); }finally { driver.quit(); } }第一个坑就是宽高必须要在设置路径之后,上面已经说明; 坑2:有些页面加载比较慢,它是默认20S没加载完成就不会加载了导致有些页面有大的图片截图下来显示一个加载中。。。 //解决如下: 设置超时时间 public static void guge(String url){ //这里设置下载的驱动路径,Windows对应chromedriver.exe Linux对应chromedriver,具体路径看你把驱动放在哪 System.setProperty("webdriver.chrome.driver", "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); //ssl证书支持 options.setCapability("acceptSslCerts", true); //截屏支持 options.setCapability("takesScreenshot", true); //css搜索支持 options.setCapability("cssSelectorsEnabled", true); options.setHeadless(true); ChromeDriver driver = new ChromeDriver(options); //设置超时,避免有些内容加载过慢导致截不到图 driver.manage().timeouts().pageLoadTimeout(1, TimeUnit.MINUTES); driver.manage().timeouts().implicitlyWait(1, TimeUnit.MINUTES); driver.manage().timeouts().setScriptTimeout(1, TimeUnit.MINUTES); try { //设置需要访问的地址 driver.get(url); //获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高; Long width = (Long)driver.executeScript("return document.documentElement.scrollWidth"); Long height =(Long) driver.executeScript("return document.documentElement.scrollHeight"); System.out.println("高度:"+height); //设置窗口宽高,设置后才能截全 driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue())); //设置截图文件保存的路径 String screenshotPath = "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\img\\imgGG.png"; File srcFile = driver.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcFile, new File(screenshotPath)); }catch (Exception e){ throw new RuntimeException("截图失败",e); }finally { driver.quit(); } }坑3:有些页面是懒加载的模式,如果滚动条不滚动到对应的位置,是不会去加载那部分类容,导致懒加载部分截图空白。 //解决如下: 模拟浏览器滚动滚动条 解决懒加载问题 public static void guge(String url){ //这里设置下载的驱动路径,Windows对应chromedriver.exe Linux对应chromedriver,具体路径看你把驱动放在哪 System.setProperty("webdriver.chrome.driver", "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); //ssl证书支持 options.setCapability("acceptSslCerts", true); //截屏支持 options.setCapability("takesScreenshot", true); //css搜索支持 options.setCapability("cssSelectorsEnabled", true); options.setHeadless(true); ChromeDriver driver = new ChromeDriver(options); //设置超时,避免有些内容加载过慢导致截不到图 driver.manage().timeouts().pageLoadTimeout(1, TimeUnit.MINUTES); driver.manage().timeouts().implicitlyWait(1, TimeUnit.MINUTES); driver.manage().timeouts().setScriptTimeout(1, TimeUnit.MINUTES); try { //设置需要访问的地址 driver.get(url); //获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高; Long width = (Long)driver.executeScript("return document.documentElement.scrollWidth"); Long height =(Long) driver.executeScript("return document.documentElement.scrollHeight"); System.out.println("高度:"+height); //这里需要模拟滑动,有些是滑动的时候才加在的 long temp_height = 0; while (true) { //每次滚动500个像素,因为懒加载所以每次等待2S 具体时间可以根据具体业务场景去设置 Thread.sleep(2000); driver.executeScript("window.scrollBy(0,500)"); temp_height += 500; if(temp_height>=height){ break; } } //设置窗口宽高,设置后才能截全 driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue())); //设置截图文件保存的路径 String screenshotPath = "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\img\\imgGG.png"; File srcFile = driver.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcFile, new File(screenshotPath)); }catch (Exception e){ throw new RuntimeException("截图失败",e); }finally { driver.quit(); } }通过以上操作,终于可以在本地(Windows)运行并且生成完美截图,开始部署在到服务器上 准备Linux环境安装Chrome浏览器以及依赖 //chrome程序 yum install https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm //chrome依赖库 yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y 安装完成之后运行各种坑又来了~~~~~~~~~~~~~~~ 坑4:在Linux服务器上报错 错误如下: java.lang.IllegalStateException: The driver is not executable: /home/soft/chrome/chromedriver at com.google.common.base.Preconditions.checkState(Preconditions.java:588) at org.openqa.selenium.remote.service.DriverService.checkExecutable(DriverService.java:150) at org.openqa.selenium.remote.service.DriverService.findExecutable(DriverService.java:141) at org.openqa.selenium.chrome.ChromeDriverService.access$000(ChromeDriverService.java:35) at org.openqa.selenium.chrome.ChromeDriverService$Builder.findDefaultExecutable(ChromeDriverService.java:159) at org.openqa.selenium.remote.service.DriverService$Builder.build(DriverService.java:355) at org.openqa.selenium.chrome.ChromeDriverService.createDefaultService(ChromeDriverService.java:94) at org.openqa.selenium.chrome.ChromeDriver.(ChromeDriver.java:157) at com.bmsoft.evidence.service.impl.ArticleServiceImpl.getFilePathByUrl(ArticleServiceImpl.java:734) at com.bmsoft.evidence.service.impl.ArticleServiceImpl.screenshot(ArticleServiceImpl.java:287) at com.bmsoft.evidence.service.impl.ArticleServiceImpl$FastClassBySpringCGLIB$dafff6e9.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:752) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at com.bmsoft.evidence.service.impl.ArticleServiceImpl$EnhancerBySpringCGLIB$52855f88.screenshot() at com.bmsoft.evidence.service.impl.AsyncServiceImpl.saveWebSiteDetail(AsyncServiceImpl.java:139) at com.bmsoft.evidence.service.impl.AsyncServiceImpl.saveWebSite(AsyncServiceImpl.java:124) at com.bmsoft.evidence.service.impl.AsyncServiceImpl$FastClassBySpringCGLIB$d0ae7c23.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:752) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 驱动执行无权限,通过赋予驱动权限来处理 //进入驱动所在文件夹后执行以下命令: chmod a+x chromedriver 坑4:有权限之后又出现新的错误,错误如下: org.openqa.selenium.WebDriverException: unknown error: Chrome failed to start: exited abnormally. (unknown error: DevToolsActivePort file doesn't exist) (The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.) Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03' System info: host: 'zf-test', ip: '127.0.0.1', os.name: 'Linux', os.arch: 'amd64', os.version: '3.10.0-514.26.2.el7.x86_64', java.version: '1.8.0_261' Driver info: driver.version: ChromeDriver remote stacktrace: #0 0x7fd05e812e89 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.W3CHandshakeResponse.lambda$errorHandler$0(W3CHandshakeResponse.java:62) at org.openqa.selenium.remote.HandshakeResponse.lambda$getResponseFunction$0(HandshakeResponse.java:30) at org.openqa.selenium.remote.ProtocolHandshake.lambda$createSession$0(ProtocolHandshake.java:126) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.Spliterators$ArraySpliterator.tryAdvance(Spliterators.java:958) at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499) 通过查找发现是一些浏览器的参数设置不对导致,设置浏览器参数 //解决如下: 模拟浏览器滚动滚动条 解决懒加载问题 public static void guge(String url){ //这里设置下载的驱动路径,Windows对应chromedriver.exe Linux对应chromedriver,具体路径看你把驱动放在哪 System.setProperty("webdriver.chrome.driver", "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); //ssl证书支持 options.setCapability("acceptSslCerts", true); //截屏支持 options.setCapability("takesScreenshot", true); //css搜索支持 options.setCapability("cssSelectorsEnabled", true); //设置浏览器参数 options.addArguments("--headless"); options.addArguments("--no-sandbox"); options.addArguments("--disable-gpu"); options.addArguments("--disable-dev-shm-usage"); options.setHeadless(true); ChromeDriver driver = new ChromeDriver(options); //设置超时,避免有些内容加载过慢导致截不到图 driver.manage().timeouts().pageLoadTimeout(1, TimeUnit.MINUTES); driver.manage().timeouts().implicitlyWait(1, TimeUnit.MINUTES); driver.manage().timeouts().setScriptTimeout(1, TimeUnit.MINUTES); try { //设置需要访问的地址 driver.get(url); //获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高; Long width = (Long)driver.executeScript("return document.documentElement.scrollWidth"); Long height =(Long) driver.executeScript("return document.documentElement.scrollHeight"); System.out.println("高度:"+height); //这里需要模拟滑动,有些是滑动的时候才加在的 long temp_height = 0; while (true) { //每次滚动500个像素,因为懒加载所以每次等待2S 具体时间可以根据具体业务场景去设置 Thread.sleep(2000); driver.executeScript("window.scrollBy(0,500)"); temp_height += 500; if(temp_height>=height){ break; } } //设置窗口宽高,设置后才能截全 driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue())); //设置截图文件保存的路径 String screenshotPath = "C:\\Users\\86186\\Desktop\\phantomjs-2.1.1-windows\\bin\\img\\imgGG.png"; File srcFile = driver.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcFile, new File(screenshotPath)); }catch (Exception e){ throw new RuntimeException("截图失败",e); }finally { driver.quit(); } }处理完以上问题 终于在服务器上不报错了,且生成了图片文件,正在高兴的时候,打开图片发现上面的文字全是方框 o(╥﹏╥)o 坑5:图片中文变成方框: 通过查询资料发现是因为系统没有中文字体导致的,然后开始安装系统中文字体 yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y 安装上面字体之后 发现还是有些字变方框,这时候我就把Windows上的一些中文字体移到Linux系统中去了,window字体位置自行百度 #1.在/usr/share/fonts目录下创建 chinese目录进行存放中文字体 mkdir -p /usr/share/fonts/chinese/ #2.为刚加入的字体设置缓存使之有效 fc-cache -fv #3.查看系统中的字体,是否已包含songti fc-list 完成以上设置,再执行截图,完美截出想要的图片 终于算搞定了~~~~~~~~~ O(∩_∩)O哈哈~ |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |