java+selenium+autoIt 实现下载(打印)功能
java+selenium+autoIt 实现下载(打印)功能
selenium是一个开源的自动化测试框架,它可以模拟用户对浏览器的操作,进行自动化的测试。但是,它不仅仅只能用来做测试。
AutoIt 是一个使用类似BASIC脚本语言的免费软件,它设计用于Windows GUI(图形用户界面)中进行自动化操作。它利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。而这是其它语言不可能做到或无可靠方法实现的(例如VBScript和SendKeys)。在这个项目中AutoIt 主要用于在浏览器中点击下载后,保存文件时,对windos弹框进行操作。
因为业务需求,需要把一个html网页转化成PDF,本来准备考虑用iText来对html转为PDF,但是我们已经拥有html的网页了,用iText感觉太麻烦,然后又找了一个第三方html->pdf,结果需要收费等一些其它原因,最终决定采用selenium+chrome+java+autol对网页进行导出PDF。
即使这个是打印成PDF,也可用于下载
环境:springboot v2.1.2 + maven + selenium 3.141.59 + chrome 71.0.3578.98
1 selenium
1.1 关于selenium
selenium是一个自动化测试框架,可以模拟用户的浏览器操作,可以和几门热门的语言相结合,例如java,python,接下来我将使用selenuim来操作chrome来模拟用户将网页保存为PDF。
1.2 selenium连接chrome
1.2.1 添加selenium的jar包
<!-- Selenium dependency -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-server</artifactId>
<version>3.141.59</version>
</dependency>
1.2.2 下载谷歌浏览器驱动
因为我用的是最新的chrome,所以下载的也是暂时最新的驱动,每个驱动对应的谷歌浏览器版本也不一样,你们可以查看相应的文档,查看自己所对应的驱动
下载完驱动之后,将驱动放置于resource目录下的driver文件夹内
1.2.3 加载WebDriver
/*获取浏览器的连接*/
public static WebDriver openAccess() {
//在idea运行的谷歌驱动路径
System.setProperty("webdriver.chrome.driver",
"src/main/resources/driver/chromedriver.exe");
//打jar包后的谷歌驱动路径
/*String driverPath = System.getProperty("user.dir")+File.separator+"driver"+ File.separator+"chromedriver.exe";*/
HashMap<String, Object> chromePrefs = new HashMap<>();
chromePrefs
.put("profile.default_content_settings.popups", 0);//设置为禁止弹出下载窗口
chromePrefs
.put("download.default_directory", downloadFilepath);//设置为文件下载路径
ChromeOptions options = new ChromeOptions();
HashMap<String, Object> chromeOptionsMap = new HashMap<>();
options.setExperimentalOption("prefs", chromePrefs);
options.addArguments("--test-type");
options.addArguments("disable-infobars");//取消Chrome正在受到自动测试软件的控制
/*
用户浏览器地址,用于加载浏览器的用户信息,
这一步将增加浏览器的性能消耗,
如果不加这一行,浏览器默认已访客模式进入浏览器,
可根据自己的需求来选择是否使用
*/
options.addArguments("user-data-dir=C:\\Users\\onegene\\AppData\\Local\\Google\\Chrome\\User Data");
DesiredCapabilities cap = DesiredCapabilities.chrome();
cap.setCapability(ChromeOptions.CAPABILITY, chromeOptionsMap);
cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
cap.setCapability(ChromeOptions.CAPABILITY, options);
WebDriver driver = null;
boolean flag = true;
while (flag) {
try {
flag = false;
driver = new ChromeDriver(cap);
//响应时间超过8秒,则重新开启浏览器连接
driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
driver.manage().window().maximize();
// driver.get(url);
} catch (Exception e) {
flag = true;
if (driver != null) {
driver.quit();
}
log.info("wait for connection browser ");
}
}
return driver;
}
①System.setProperty("webdriver.chrome.driver","src/main/resources/driver/chromedriver.exe");这一步用于在IDEA中运行的是否加载驱动,如果,打成jar包之后,加载驱动的话,应该用下面一行加载驱动,驱动放在与jar包同目录的dreiver目录下
String driverPath = System.getProperty("user.dir")+File.separator+"driver"+ File.separator+"chromedriver.exe";
System.setProperty("webdriver.chrome.driver",driverPath);
②options.addArguments("user-data-dir=" + DriverPathUtils.getChromePath());用户浏览器地址,用于加载浏览器的用户信息,这一步将增加浏览器的性能消耗,如果不加这一行,浏览器默认已访客模式进入浏览器,可根据自己的需求来选择是否使用
1.3 加载url,进行元素操作
webDriver.get(url);//自己定义
Thread.sleep(1000);
//根绝class寻找元素,并且点击
WebElement addpBtn = webDriver.findElement(By.className("addp"));
addpBtn.click();
Thread.sleep(1000);
//根据id寻找元素,并且点击
WebElement genLayoutBtn = webDriver.findElement(By.id("genLayout"));
genLayoutBtn.click();
注:selenium切换tab,并且关闭
String currentWin = webDriver.getWindowHandle();
Set<String> handles = webDriver.getWindowHandles();
for (String handle : handles) {
if (currentWin.equals(handle)) continue;
webDriver = webDriver.switchTo().window(handle);
}
webDriver.close();
1.4调起打印事件
调起如下的谷歌浏览器打印事件

调起浏览器的打印事件有以下两种方法:
① 点击鼠标右键,然后点击打印按钮
②按住键盘的Ctrl+P
显而易见,第②中方法更实用,所以我们采用第②种
我查看了selenium的键盘事件,发现是有键盘事件的,调起方法如下:
Actions action = new Actions(driver);
action.keyDown(Keys.CONTROL);// 按下 Ctrl 键
action.sednKeys("p")//按下P键
action.keyUp(Keys.CONTROL);// 释放 Ctrl 键
action.perform()//发送组合按键
本来以为操作键盘的方法很简单,但是不知道为啥chrome一直无法调起键盘事件,谷歌了很久,也没有找到原因,网上也有很多人说无法调起。于是查看jdk文档,发现java提供了一个操作键盘事件的类。如下

所以,我就用以下方法来实现键盘事件Ctrl+P
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_CONTROL);
本以为事情终于解决了,然后才发现,SpringBoot无法启动这个键盘事件,百度之后,才发现有两种实现的办法
①启动SpringBoot钱,给虚拟机添加参数-ea -Djava.awt.headless=false
②在SpringBoot启动类中添加代码,开启awt
public static void main(String[] args) {
System.setProperty("java.awt.headless", "false");
SpringApplication.run(SeleniumApplication.class, args);
}
1.5 进入保存界面
打印界面进入保存界面只需要按下回车键,所以只需按照上一步操作键盘点击回车键就好了
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_CONTROL);
//睡眠7S,因为谷歌浏览器进入打印要先进行渲染,这个需要一段时间
Thread.sleep(7000);
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
2 autolt
AutoIt 目前最新是v3版本,这是一个使用类似BASIC脚本语言的免费软件,它设计用于Windows GUI(图形用户界面)中进行自动化操作。它利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。而这是其它语言不可能做到或无可靠方法实现的
2.1 autolt基本脚本语法
进入到了另存为得界面,这个时候selenium就基本上无法进行操作了,因为selenium只对谷歌浏览器进行操作,不对window窗口进行操作,所以这个时候就需要autolt进行处理了。autolt是一个脚本语言,因为我们只需要保存一个文件,所以并不需要那么深入,所以下面我讲下autolt基本使用方法
2.1.1 安装完软件之后,各个文件的作用

- 编辑器:用于编写脚本语言,并且进行调试,按住
F5进行调试 - 运行器:将脚本语言进行运行
- 转脚本为exe:将编写的脚本转换成exe文件,用于java或者python直接运行
- 查看窗口信息:用于获取将要操作窗口的基本信息,例如将要操作按钮和编辑框的信息等等
2.1.2 查看窗口信息

查看窗口信息的方法:按住Finder Tool的,然后拖拽到你要操作的位置,这个时候查看Control窗口,就能得到你要操作的元素信息
- Title:当前窗口的标题
- Calss:当前元素的类型,例如当前窗口为编辑框,则这里显示Edit
- Instance:这个是这个窗口的第一个Edit,所以Instance为1
- ClassnameNN:可以作为当前元素的唯一id,但是没有AdvancedModel准确
2.2 autolt保存文件
#该脚本的语法是: ;分号代表注释,为了博客好看,我先把;换成#
##ControlFocus ( "title", "窗口文本", controlID) 设置输入焦点到指定窗口的某个控件上
#WinWait ( "title题" , "窗口文本" , 超时时间 ) 暂停脚本的执行直至指定窗口存在(出现)为止
#ControlSetText ( "title", "窗口文本", controlID, "新文本" ) 修改指定控件的文本
#Sleep ( 延迟 ) 使脚本暂停指定时间段
#ControlClick ( "title", "窗口文本", 控件ID , 按钮 , 点击次数 ) 向指定控件发送鼠标点击命令
#其中,title即AutoIt Window Info识别出的Title字段,controlID即AutoIt Window Info识别
#出的Class和Instance的拼接,如上图拼接后的结果应为:Button1
#ControlClick(
#ControlClick("另存为","保存","Button2")
ControlFocus("另存为","text","1001")
WinWait("[CLASS:#32770]","",100)
ControlSetText("另存为","","[CLASS:Edit; INSTANCE:1]","$CmdLine[1]")
Sleep(1500)
ControlClick("另存为","保存","Button2")
2.3 autolt打包成exe
运行转脚本为exe的文件,将其转换成exe文件,放入resource目录下的driver下面
2.4 java运行exe文件
//第一个参数是exe路径,后面是执行cmd得参数,这个也就是对应保存PDF的名称
String[] commandArray = {"src/main/resources/driver/pdf.exe", sample.getCode() + ".pdf"};
runtime.exec(commandArray);
3 结尾
虽然我写的这个博客是关于java+selenium+autolt将html打印成PDF,但是也可以用到下载文件里边,原理是一样的。在进行爬虫的时候,经常要遇到下载文件的业务,这样可以很好的完成。
java+selenium+autoIt 实现下载(打印)功能的更多相关文章
- Python + Selenium + AutoIt 模拟键盘实现另存为、上传、下载操作详解
前言 在web页面中,可以使用selenium的定位方式来识别元素,从而来实现页面中的自动化,但对于页面中弹出的文件选择框,selenium就实现不了了,所以就需引用AutoIt工具来实现. Auto ...
- 《手把手教你》系列技巧篇(五十七)-java+ selenium自动化测试-下载文件-下篇(详细教程)
1.简介 前边几篇文章讲解完如何上传文件,既然有上传,那么就可能会有下载文件.因此宏哥就接着讲解和分享一下:自动化测试下载文件.可能有的小伙伴或者童鞋们会觉得这不是很简单吗,还用你介绍和讲解啊,不说就 ...
- selenium+java利用AutoIT实现文件上传
转自https://www.cnblogs.com/yunman/p/7112882.html?utm_source=itdadao&utm_medium=referral 1.AutoIT介 ...
- Atitit.java swing打印功能 api attilax总结
Atitit.java swing打印功能 api attilax总结 1. 打印方式有三种:2 1.1. 一是不经过任何修改,直接调用javascript中的window.print()打印.2 ...
- Atitit.收银机小票打印功能的设计 java php c#.net版本
Atitit.收银机小票打印功能的设计 java php c#.net版本 1. 1. 打印方式有4种:1 1.1. 1.1. 一是不经过任何修改,直接调用javascript中的window.pr ...
- Java实现打印功能-AWT Graphics2D
Java实现打印功能 用java实现打印,java.awt中提供了一些打印的API,要实现打印,首先要获得打印对象,然后继承Printable实现接口方法print,以便打印机进行打印,最后用用Gra ...
- java实现自动静默打印功能
最近接到一个需求,要求实现自动打印功能,一般网页打印pdf需要借助浏览器的pdf组件,而且还要弹出打印窗口,再点击打印才能实现. 那么如何实现自动打印了,从点击自己网页上3次缩减到点击一次了? 一 ...
- 《手把手教你》系列技巧篇(五十六)-java+ selenium自动化测试-下载文件-上篇(详细教程)
1.简介 前边几篇文章讲解完如何上传文件,既然有上传,那么就可能会有下载文件.因此宏哥就接着讲解和分享一下:自动化测试下载文件.可能有的小伙伴或者童鞋们会觉得这不是很简单吗,还用你介绍和讲解啊,不说就 ...
- 《手把手教你》系列技巧篇(五十五)-java+ selenium自动化测试-上传文件-下篇(详细教程)
1.简介 在实际工作中,我们进行web自动化的时候,文件上传是很常见的操作,例如上传用户头像,上传身份证信息等.所以宏哥打算按上传文件的分类对其进行一下讲解和分享. 2.为什么selenium没有提供 ...
- 《手把手教你》系列基础篇(八十六)-java+ selenium自动化测试-框架设计基础-Log4j实现日志输出(详解教程)
1.简介 自动化测试中如何输出日志文件.任何软件,都会涉及到日志输出.所以,在测试人员报bug,特别是崩溃的bug,一般都要提供软件产品的日志文件.开发通过看日志文件,知道这个崩溃产生的原因,至少知道 ...
随机推荐
- System.Runtime.Serialization.SerializationException:“二进制流“0”不包含有效的 BinaryHeader。这可能是由于无效流,或由于在序列化和反序列化之间的对象版本更改。
var buffer = new byte[1024]; using (var ms = new MemoryStream(buffer)) { //xxx } 原因是buffer的长度过短,当接受到 ...
- B1031 查验身份证 (15 分)
描述 一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5 ...
- 微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析)
微软开源bitnet b1.58大模型,应用效果测评(问答.知识.数学.逻辑.分析) 目 录 1. 前言... 2 2. 应用部署... 2 3. 应用效果... ...
- docker-compose用法
以下的示例搭建龙一个wordpress博客 services: mysql: image: mysql:latest environment: - MYSQL_ROOT_PASSWORD=123456 ...
- 「Temp」CSP-S 2023 JL 迷惑代码大赏
(欢迎投稿.) 在 \(213\) 份代码中共查找到 \(21\) 个 //freopen,来自 JL-S00031.JL-S00045.JL-S00047.JL-S00085.JL-S00123.J ...
- Vue 学习笔记 [Part 4]
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 一. 组件化开发 1.1. 父子组件的访问 1.2. slot的使用 二. 前端模块化 2.1. 为什么要使用模块化 2.2. ES6中模块化 ...
- Springboot笔记<9>使用Javaweb原生组件
使用Javaweb原生组件 Javaweb的三大组件:servlet,Filter,Listener,Servlet 3.0 提供了以下 3 个注解: @WebServlet:用于声明一个 Servl ...
- 数据库的DML与DQL语句
1: DML语句 insert into values 1 insert into 表 values(值1,值2,值n); 2 insert into 表(字段1,字段2,字段n) values( ...
- Java常用类Object
1 package com.lv.study.pm; 2 3 public class TestObject { 4 5 public static void main(String[] args) ...
- 【UNIAPP】canvas画布不能绘图片
已知原因1: 当使用 v-if 时,会失效 解决方法1: 如果需要暂时隐藏可以使用 z-index