java 实现网址的截图

发布时间 2023-09-04 14:29:50作者: 一说烟雨

 

maven 引入

<!--自动化测试工具,需要去其他网址下第三方包-->
<dependency>
  <groupId>org.seleniumhq.selenium</groupId>
  <artifactId>selenium-java</artifactId>
  <version>3.141.59</version>
   <exclusions>
    <exclusion>
     <artifactId>guava</artifactId>
     <groupId>com.google.guava</groupId>
    </exclusion>
   </exclusions>
  </dependency>
  <dependency>
  <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
    <version>23.0</version>
    </dependency>
   <dependency>
   <groupId>com.google.code.gson</groupId>
     <artifactId>gson</artifactId>
    <version>2.8.2</version>
  </dependency>

  

下载相关浏览器chrome

(windows)https://www.chromedownloads.net/chrome64win/
windows会自己更新,需要自己去禁止更新,不然测着测着,浏览器升级了(除非你旧版本打开以后,就不要关闭),导致代码报错

(linux)https://www.chromedownloads.net/chrome64linux/
linux系统不会自动更新的,不要担心

下载相关浏览器chromedriver驱动

我这边下载的也是98.0.4758.102版本
https://registry.npmmirror.com/binary.html?path=chromedriver/98.0.4758.102/

 

测试代码

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.epoint.third.apache.commons.io.FileUtils;
import com.linewell.gov.hoox.utils.log.LogUtil;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;

import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 条件:需要谷歌浏览器版本和驱动版本一张
 */
public class SeleniumTools {

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Timestamp now1 = new Timestamp(startTime);
        System.out.println("now1:" + now1);
        for (int i = 0; i < 3; i++) {
            try {
                guge("D:/guge/img"+"/"+System.currentTimeMillis()+".png",
                        "https://mpage.taobao.com/hd/download.html",
                        "123");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long between = DateUtil.between(new Date(startTime), new Date(), DateUnit.SECOND);
        System.out.println("相差秒"+between);
        System.out.println("相差分钟"+between/60);


    }


    //解决如下: 模拟浏览器滚动滚动条 解决懒加载问题
    public static void guge(String hzdtpwzPath, String url, String nhhzdtoken) throws IOException {
        LogUtil.info("=====guge=========");
        LogUtil.info(hzdtpwzPath);
        LogUtil.info(url);
        LogUtil.info(nhhzdtoken);
        // 根据系统来添加不同的驱动路径
        String os = System.getProperty("os.name");
        LogUtil.info(os);
        String driverPath ="";
        if (StrUtil.containsIgnoreCase(os, "Windows")) {//微软系统
            driverPath+="D:\\chromedriver_win32 (98.0.4758.102)\\chromedriver.exe";
        //程序执行,核心代码
            processCMD("taskkill /F /im chromedriver.exe",1);
        } else {//linux系统
            driverPath+="/usr/local/xxxx/ChromeDriver/chromedriver_linux64/chromedriver";
            //程序执行,核心代码
            processCMD("ps -ef | grep Chrome | grep -v grep  | awk '{print \"kill -9 \"$2}' | sh",2);
        }

        //频繁的启动关闭,会增加一个比较明显的延时导致浏览器进程不被关闭的情况发生,
        // 为了避免这一状况我们可以通过ChromeDriverService来控制ChromeDriver进程的生死,
        // 达到用完就关闭的效果避免进程占用情况出现(Running the  server in a child process)
        ChromeDriverService service =new  ChromeDriverService.Builder().usingDriverExecutable(new File(driverPath)).usingAnyFreePort().build(); // 新建service 方便后面关闭chromedriver
        service.start(); // 开启服务

        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.addArguments("--no-zygote");
        //设置无头模式,一定要设置headless,否则只能截出电脑屏幕大小的图!!!
        options.setHeadless(true);
        WebDriver driver = new ChromeDriver(service,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);
            //先登录,再设置cookies
            Cookie c1 = new Cookie("token", nhhzdtoken);
            driver.manage().addCookie(c1);
            //设置需要访问的地址
            driver.get(url);
            //获取高度和宽度一定要在设置URL之后,不然会导致获取不到页面真实的宽高;
            Long width = (Long) ((ChromeDriver) driver).executeScript("return document.documentElement.scrollWidth");
            Long height = (Long) ((ChromeDriver) driver).executeScript("return document.documentElement.scrollHeight");
            LogUtil.info("宽带:" + width);
            LogUtil.info("高度:" + height);
            //这里需要模拟滑动,有些是滑动的时候才加在的
            long temp_height = 0;
            while (true) {
                //每次滚动500个像素,因为懒加载所以每次等待2S 具体时间可以根据具体业务场景去设置
                Thread.sleep(1000);
                ((ChromeDriver) driver).executeScript("window.scrollBy(0,500)");
                temp_height += 500;
                if (temp_height >= height) {
                    break;
                }
            }
            //设置窗口宽高,设置后才能截全
            driver.manage().window().setSize(new Dimension(width.intValue()+1120, height.intValue()+303));
            //设置截图文件保存的路径
            String screenshotPath = hzdtpwzPath;
            File srcFile = ((ChromeDriver) driver).getScreenshotAs(OutputType.FILE);
            FileUtils.copyFile(srcFile, new File(screenshotPath));
            LogUtil.info("设置浏览器截图文件保存的路径:" + screenshotPath);
        } catch (Exception e) {
            throw new RuntimeException("截图失败", e);
        } finally {
            //close仅仅关闭了当前页面,并未关闭chrome。
            //使用quit则会真正退出chrome,结束进程。
            //两者一起使用,才能避免频繁的启动关闭出现的卡住现象(重点)
            driver.close();
            driver.quit();
            service.stop();
        }
    }

    //直接杀进程
    public static int processCMD(String commend,int type) {
        //正常写 linux命令即可 、比如:mkdir xx/touch b.txt/sh start.sh/sh stop.sh
        int i = 0;
        Process process =null;
        //程序执行,核心代码
        try {
            if(type==1){
                //cmd /c dir 是执行完dir命令后关闭命令窗口。看需调整
                String[] cmd = new String[]{"cmd","/c",commend};
                process = Runtime.getRuntime().exec(cmd);
                //也可以直接使用 process = Runtime.getRuntime().exec(commend)
            }else{
                //要想保证linux环境下命令能够执行成功,必须使用String[]
                String[] cmd = new String[]{"sh","-c",commend};
                process = Runtime.getRuntime().exec(cmd);
            }
            i = process.waitFor();
            System.out.println("执行kill进程命令结果:" + i);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return i;
    }


    //通常,安全编码规范中都会指出:使用Process.waitFor()的时候,
    //可能导致进程阻塞,甚至死锁。
    //使用java代码执行shell脚本,执行后会发现Java进程和Shell进程都会挂起,无法结束。
    public static int processCMD2(String commend) {
        //正常写 linux命令即可 、比如:mkdir xx/touch b.txt/sh start.sh/sh stop.sh
        int i = 0;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(commend);
            //获取进程的标准输入流
            final InputStream is1 = process.getInputStream();
            //获取进城的错误流
            final InputStream is2 = process.getErrorStream();
            //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
            new Thread(() -> {
                BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
                try {
                    String line1 = null;
                    while ((line1 = br1.readLine()) != null) {
                        if (line1 != null) {
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        is1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            new Thread(() -> {
                BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
                try {
                    String line2 = null;
                    while ((line2 = br2.readLine()) != null) {
                        if (line2 != null) {
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        is2.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            //可能导致进程阻塞,甚至死锁
            i = process.waitFor();
        } catch (Exception ex) {
            ex.printStackTrace();
            try {
                process.getErrorStream().close();
                process.getInputStream().close();
                process.getOutputStream().close();
            } catch (Exception ee) {
            }
        }
        LogUtil.info("CMD2-执行kill进程命令:" + commend);
        System.out.println("CMD2-执行kill进程命令:" + commend);
        LogUtil.info("CMD2-执行kill进程命令结果:" + i);
        System.out.println("CMD2-执行kill进程命令结果:" + i);
        return i;
    }

}

  

 

转自 https://blog.csdn.net/qq_20236937/article/details/132231095