应用场景
有个项目需要将网页上面的图表放生成的word报告中,页面上面的图表是用Echarts做的,因为要求word报告中的图表和页面上的图表保持一致,所以将页面上面的图表截图保存到数据库中,然后从数据库中查询到图片放到word报告中。为了实现自动截图保存,项目采用selenium打开chrome浏览器,访问页面后通过js截图,然后下载到文件夹中,程序运行了很长一段时间都没有问题,最近chrome浏览器自动更新到了75.0.3770版,突然发现页面截图后下载失败了,浏览器提示“下载失败”。

系统环境
服务器:windows server 2008 64位
JDK:1.8.0_161
浏览器:chrome 75.0.3770
selenium-java:3.141.59
chromedriver:75.0.3770.90

问题原因
在保存下载的图片的时候,设置了文件的保持路径,设置如下:

chromePrefs.put("download.default_directory", "E:/picture");

正是这个路径设置出现了问题,windows下必须是“\”而不是“/”,早期的chrome版本中这个路径设置后并未起作用,下载的时候使用的是chrome默认的下载路径,在最新的chrome版本中这个设置突然起作用了,因为路径错了,导致图片下载失败,正确配置如下:

chromePrefs.put("download.default_directory", "E:\\picture");

拓展知识:斜杆与反斜杆的区别
正斜杠,又称左斜杠,符号是"/";反斜杠,也称右斜杠,符号是"\"。
Unix使用斜杆/ 作为路径分隔符,web应用最开始跑在Unix系统上面,所以目前所有的网络地址都采用 斜杆/ 作为分隔符。
Windows由于使用 斜杆/ 作为DOS命令提示符的参数标志了,为了不混淆,所以采用 反斜杠\ 作为路径分隔符。所以目前windows系统上的资源管理器中都是用 反斜杠\ 作为路径分隔符。随着发展,DOS系统已经被淘汰了,命令提示符也用的很少,斜杆和反斜杠在大多数情况下可以互换,没有影响。
很多编译器使用反斜杠作为转义字符的开头,所以“\\”代表向内存中输入一个反斜杠。

示例代码

public static void main(String[] args) {
		System.setProperty("webdriver.chrome.driver","C:\\ChromePortable\\chromedriver.exe");

        ChromeOptions options = new ChromeOptions();
        options.setBinary("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"); 
        
        Map<String, Object> chromePrefs = new HashMap<String, Object>();
        chromePrefs.put("profile.default_content_settings.popups", 0);
        chromePrefs.put("download.default_directory", "E:\\picture");
        chromePrefs.put("profile.content_settings.exceptions.automatic_downloads.*.setting", 1);
        chromePrefs.put("download.prompt_for_download", false);

        options.setExperimentalOption("prefs", chromePrefs);
        
		ChromeDriver driver = new ChromeDriver(options);
		
		try {
			driver.get("http://172.16.0.52:8866/ljzx/reportPictureApi/toCompanyFinance?compName=北京小桔科技有限公司#/");
			
			// 等待10000毫秒,供下载图片
			Thread.sleep(10000);
			
			driver.get("http://172.16.0.52:8866/ljzx/reportPictureApi/toCompanyLawInfo?compName=北京小桔科技有限公司#/");
			
			// 等待15000毫秒,供下载图片
			Thread.sleep(15000);
			
			driver.quit();
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
			
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}