Commit 025a4e15 authored by shanglipeng's avatar shanglipeng

代码完善

parent f6bd2d52
"/Google/Chrome/Application/chrome.exe" --remote-debugging-port=9222 --user-data-dir="c:/selenium/ChromeProfile" --allow-pre-commit-input --disable-background-networking --disable-backgrounding-occluded-windows --disable-client-side-phishing-detection --disable-default-apps --disable-hang-monitor --disable-infobars --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-blink-features=ShadowDOMV0 --enable-logging --ignore-certificate-errors --log-level=3 --no-service-autorun --password-store=basic --start-maximized --test-type --use-mock-keychain --flag-switches-begin --flag-switches-end
\ No newline at end of file
package com.greatchn; package com.greatchn;
import com.greatchn.kits.ChromeKits;
import com.greatchn.yzh.TaskExecutor; import com.greatchn.yzh.TaskExecutor;
/** /**
...@@ -9,7 +10,9 @@ import com.greatchn.yzh.TaskExecutor; ...@@ -9,7 +10,9 @@ import com.greatchn.yzh.TaskExecutor;
* @since 1.0.0 * @since 1.0.0
*/ */
public class Main { public class Main {
public static void main(String[] args) { public static void main(String[] args) throws Exception {
ChromeKits.killBrowser();
ChromeKits.utilBrowserStart("./files/chrome_no_proxy.bat");
new TaskExecutor(); new TaskExecutor();
} }
} }
\ No newline at end of file
...@@ -76,7 +76,7 @@ public abstract class BaseEtax { ...@@ -76,7 +76,7 @@ public abstract class BaseEtax {
return this.config; return this.config;
} }
protected RpaCore rpa() { public RpaCore rpa() {
return this.rpa; return this.rpa;
} }
......
package com.greatchn.kits;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Date;
public class ChromeKits {
public static void killBrowser(){
ProcessKits.killProcess(Arrays.asList( "firefox","geckodriver","crashreporter","chromedriver","chrome"));
}
//创建浏览器
public static String utilBrowserStart(String batPath) throws Exception
{
Runtime rt = Runtime.getRuntime();
try
{
Process process = rt.exec(new File(batPath).getAbsolutePath());
// 获取启动返回信息
InputStreamReader isr = new InputStreamReader(process.getErrorStream());
BufferedReader br = new BufferedReader(isr);
long startTime = new Date().getTime();
String browserWs = "";
while (true)
{
if (new Date().getTime() - startTime >= 60000*2)
{
break;
}
browserWs = br.readLine();
if (browserWs != null && browserWs.startsWith("DevTools"))
{
browserWs = browserWs.substring(browserWs.indexOf("ws:"));
break;
}
else
{
Thread.sleep(100);
}
}
if (StringUtils.isEmpty(browserWs))
{
throw new RuntimeException("初始化chrome失败");
}
System.out.println(browserWs);
return browserWs;
}
catch (Exception e)
{
throw e;
}
}
}
package com.greatchn.kits;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.List;
public class ProcessKits
{
/**
* 判断指定进程是否存在
*
* @param processName
* @return
*/
public static Boolean isProcessExist(String processName)
{
try
{
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("win"))
{
return isWindowsProcessExist(processName);
}
if (os.toLowerCase().startsWith("lin"))
{
return isLunuxProcessExist(processName);
}
else
{
return false;
}
}
catch (Exception e)
{
return false;
}
}
public static boolean isLunuxProcessExist(String processName)
{
BufferedReader bufferedReader = null;
try
{
Process proc = Runtime.getRuntime().exec("ps -e");
bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
if (line.contains(processName)) // 判断是否存在
{
return true;
}
}
return false;
}
catch (Exception ex)
{
ex.printStackTrace();
return false;
}
finally
{
if (bufferedReader != null)
{
try
{
bufferedReader.close();
}
catch (Exception ex)
{
}
}
}
}
public static boolean isWindowsProcessExist(String processName)
{
BufferedReader bufferedReader = null;
try
{
String cmd = MessageFormat.format("{0}\\system32\\tasklist.exe",System.getenv("windir"));
Process proc = Runtime.getRuntime().exec(cmd);
bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
System.out.println(line);
if (line.contains(processName)) // 判断是否存在
{
return true;
}
}
return false;
}
catch (Exception ex)
{
ex.printStackTrace();
return false;
}
finally
{
if (bufferedReader != null)
{
try
{
bufferedReader.close();
}
catch (Exception ex)
{
}
}
}
}
public static Boolean startProcess(List<String> exeFileFullPathNameList)
{
try
{
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("win"))
{
startWindowsProcess(exeFileFullPathNameList);
}
if (os.toLowerCase().startsWith("lin"))
{
startLinuxProcess(exeFileFullPathNameList);
}
else
{
return false;
}
return true;
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
return false;
}
}
private static void startWindowsProcess(List<String> exeFileFullPathNameList)
{
try
{
Runtime runtime = Runtime.getRuntime();
for (String string : exeFileFullPathNameList)
{
runtime.exec(string);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private static void startLinuxProcess(List<String> exeFileFullPathNameList)
{
try
{
// 如果是 linux系统
for (String processName : exeFileFullPathNameList)
{
// String commandString = MessageFormat.format("ps -ef | grep {0} | grep -v grep | awk '''{'print $2'}''' | xargs kill -9", processName);
System.out.println(processName);
// 当需要执行的linux命令带有管道符时(例如:ps -ef|grep java),用上面的方法是不行的,解决方式是将需要执行的命令作为参数传给shell
String[] cmds = { "/bin/sh", "-c", processName };
Runtime.getRuntime().exec(cmds);
}
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 根据进程名称集合结束进程
*
* @param processNameList
* 进程名称集合 例如firefox,chrome 不带后缀
* @return
*/
public static Boolean killProcess(List<String> processNameList)
{
try
{
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("win"))
{
killWindowsProcess(processNameList);
}
if (os.toLowerCase().startsWith("lin"))
{
killLinuxProcess(processNameList);
}
else
{
return false;
}
return true;
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
return false;
}
}
/**
* 在windows环境下根据进程名称结束进程
*
* @param processNameList
* 进程名称集合
*/
private static void killWindowsProcess(List<String> processNameList)
{
try
{
// 如果是 windows系统
for (String processName : processNameList)
{
// String commandString=MessageFormat.format("taskkill /f /IM phantomjs.exe", arg1)
String commandString = MessageFormat.format("taskkill /f /IM {0}.exe", processName);
Runtime.getRuntime().exec(commandString);
}
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 在Linux环境下根据进程名称结束进程
*
* @param processNameList
* 进程名称集合
*/
private static void killLinuxProcess(List<String> processNameList)
{
try
{
// 如果是 linux系统
for (String processName : processNameList)
{
String commandString = MessageFormat.format("ps -ef | grep {0} | grep -v grep | awk '''{'print $2'}''' | xargs kill -9", processName);
System.out.println(commandString);
// 当需要执行的linux命令带有管道符时(例如:ps -ef|grep java),用上面的方法是不行的,解决方式是将需要执行的命令作为参数传给shell
String[] cmds = { "/bin/sh", "-c", commandString };
Runtime.getRuntime().exec(cmds);
}
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
}
package com.greatchn.rpa; package com.greatchn.rpa;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.greatchn.kits.JacksonKits; import com.greatchn.kits.JacksonKits;
import com.greatchn.kits.RandomKits; import com.greatchn.kits.RandomKits;
...@@ -13,22 +15,30 @@ import net.lightbody.bmp.client.ClientUtil; ...@@ -13,22 +15,30 @@ import net.lightbody.bmp.client.ClientUtil;
import net.lightbody.bmp.core.har.Har; import net.lightbody.bmp.core.har.Har;
import net.lightbody.bmp.proxy.CaptureType; import net.lightbody.bmp.proxy.CaptureType;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService; import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v109.network.Network;
import org.openqa.selenium.devtools.v109.network.model.Response;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.WebDriverWait;
import java.text.MessageFormat;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap; import java.util.*;
import java.util.List; import java.util.concurrent.ConcurrentHashMap;
import java.util.Objects; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* 自动化机器人对象,对 selenium 功能进行封装,方便后期使用 * 自动化机器人对象,对 selenium 功能进行封装,方便后期使用
...@@ -78,6 +88,11 @@ public class RpaCore { ...@@ -78,6 +88,11 @@ public class RpaCore {
*/ */
private Point browserOffset; private Point browserOffset;
private Thread heartThread = null;
private Map<String, Date> heartThreadCmd = new HashMap<>();
private final static String ENTER = "enter";
/* ------------------------- 构造方法 ------------------------- */ /* ------------------------- 构造方法 ------------------------- */
...@@ -87,11 +102,34 @@ public class RpaCore { ...@@ -87,11 +102,34 @@ public class RpaCore {
* @param config 配置参数 * @param config 配置参数
*/ */
public RpaCore(RpaConfig config) { public RpaCore(RpaConfig config) {
this.config = config; this.config = config;
this.scale = config.getScale(); this.scale = config.getScale();
if (config.getRpa().isAutoCreate()) { if (config.getRpa().isAutoCreate()) {
this.create(); this.create();
} }
heartThread = new Thread(() -> {
while (true) {
try {
if (MapUtil.isEmpty(this.heartThreadCmd)) {
TimeUnit.SECONDS.sleep(1L);
continue;
}
// 获取回车命令
Date date = this.heartThreadCmd.get(ENTER);
if (date != null && System.currentTimeMillis() > date.getTime()) {
//发送回车命令
WinApi.enter();
this.clearCmd();
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " heartThread已执行WinApi.enter()");
}
} catch (Exception e) {
}
}
});
heartThread.start();
} }
/* ------------------------- 核心对象处理 ------------------------- */ /* ------------------------- 核心对象处理 ------------------------- */
...@@ -146,13 +184,12 @@ public class RpaCore { ...@@ -146,13 +184,12 @@ public class RpaCore {
this.createProxy(); this.createProxy();
} }
var options = new ChromeOptions(); var options = new ChromeOptions();
options.addArguments( //自动启动浏览器
"--start-maximized", if (this.config.isRemoteDebugging() == false) {
"disable-infobars", //Logger.getLogger("org.openqa.selenium.devtools").setLevel(Level.OFF);
"--test-type", options.addArguments("--log-level=3");
"--ignore-certificate-errors" options.addArguments("--start-maximized", "disable-infobars", "--test-type", "--ignore-certificate-errors");
); options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation", "enable-logging"});
options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
options.setExperimentalOption("prefs", new HashMap<String, Boolean>(3) { options.setExperimentalOption("prefs", new HashMap<String, Boolean>(3) {
{ {
this.put("download.prompt_for_download", false); this.put("download.prompt_for_download", false);
...@@ -163,13 +200,20 @@ public class RpaCore { ...@@ -163,13 +200,20 @@ public class RpaCore {
if (this.config.getRpa().isFullScreen()) { if (this.config.getRpa().isFullScreen()) {
options.addArguments("--kiosk"); options.addArguments("--kiosk");
} }
options.addArguments("--user-data-dir=/selenium/ChromeProfile");
}
//手动启动浏览器
if (this.config.isRemoteDebugging() == true) {
options.setExperimentalOption("debuggerAddress", this.config.getRemoteDebuggingIP() + ":" + this.config.getRemoteDebuggingPort());
}
//Mobo
if (this.config.getRpa().getProxy().isEnable()) { if (this.config.getRpa().getProxy().isEnable()) {
var seleniumProxy = ClientUtil.createSeleniumProxy(proxy); var seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
options.setCapability(CapabilityType.PROXY, seleniumProxy); options.setCapability(CapabilityType.PROXY, seleniumProxy);
} }
options.setCapability("acceptInsecureCerts", true); options.setCapability("acceptInsecureCerts", true);
var builder = new ChromeDriverService.Builder(); var builder = new ChromeDriverService.Builder();
builder.usingDriverExecutable(this.config.getSelenium().getExe()); builder.usingDriverExecutable(this.config.getSelenium().getExe());
var service = builder.build(); var service = builder.build();
...@@ -177,6 +221,17 @@ public class RpaCore { ...@@ -177,6 +221,17 @@ public class RpaCore {
if (this.config.getRpa().getCookies().isClean()) { if (this.config.getRpa().getCookies().isClean()) {
this.driver.manage().deleteAllCookies(); this.driver.manage().deleteAllCookies();
} }
HashMap<String, Object> cdpCmd = new HashMap<String, Object>();
cdpCmd.put("source", """
(function() {
try {
window.alert = function() {}
window.confirm = function() {return true;}
} catch (e) {
}
})()
""");
Map<String, Object> tmp_res = driver.executeCdpCommand("Page.addScriptToEvaluateOnNewDocument", cdpCmd);
this.create = true; this.create = true;
} }
...@@ -219,18 +274,32 @@ public class RpaCore { ...@@ -219,18 +274,32 @@ public class RpaCore {
* 开启一个新的监听集合 * 开启一个新的监听集合
*/ */
public Har newHar() { public Har newHar() {
//Mobo模式开启
if (this.config.isNetworkProxy()==false) {
if (!this.config.getRpa().getProxy().isEnable()) { if (!this.config.getRpa().getProxy().isEnable()) {
throw new IllegalStateException("当前 Robot 对象没有开启网络代理!"); throw new IllegalStateException("当前 Robot 对象没有开启网络代理!");
} }
this.endHar(); this.endHar();
return this.proxy.newHar(String.format("robot_har_%d", this.harCount.getAndAdd(DELTA))); return this.proxy.newHar(String.format("robot_har_%d", this.harCount.getAndAdd(DELTA)));
} }
//chrome模式开启
else {
this.enableNetWork();
return null;
}
}
/** /**
* 结束当前网络监听集合 * 结束当前网络监听集合
*/ */
public void stopHar() { public void stopHar() {
if (this.config.isNetworkProxy()==false) {
this.proxy.waitForQuiescence(QUIT_PERIOD, QUIT_PERIOD, TimeUnit.SECONDS); this.proxy.waitForQuiescence(QUIT_PERIOD, QUIT_PERIOD, TimeUnit.SECONDS);
return;
}
else {
this.closeNetWork();
}
} }
/** /**
...@@ -251,15 +320,14 @@ public class RpaCore { ...@@ -251,15 +320,14 @@ public class RpaCore {
* @return 监听响应 * @return 监听响应
*/ */
public String listen(String uri, long timeout) { public String listen(String uri, long timeout) {
//Mobo模式的network
if (this.config.isNetworkProxy()==false) {
final var outTime = System.currentTimeMillis() + timeout * 1000; final var outTime = System.currentTimeMillis() + timeout * 1000;
try { try {
while (true) { while (true) {
var har = this.proxy.getHar(); var har = this.proxy.getHar();
for (var entry : har.getLog().getEntries()) { for (var entry : har.getLog().getEntries()) {
if (!Objects.isNull(entry.getRequest()) if (!Objects.isNull(entry.getRequest()) && entry.getRequest().getUrl().contains(uri) && !Objects.isNull(entry.getResponse()) && entry.getResponse().getStatus() == 200) {
&& entry.getRequest().getUrl().contains(uri)
&& !Objects.isNull(entry.getResponse())
&& entry.getResponse().getStatus() == 200) {
return entry.getResponse().getContent().getText(); return entry.getResponse().getContent().getText();
} }
} }
...@@ -275,6 +343,11 @@ public class RpaCore { ...@@ -275,6 +343,11 @@ public class RpaCore {
this.stopHar(); this.stopHar();
} }
} }
//chrome的network
else{
return this.listenNetWorkCenter(uri,timeout*1000L);
}
}
/** /**
* 监听指定 uri 返回内容,并将返回内容反序列化为 JsonNode 对象 * 监听指定 uri 返回内容,并将返回内容反序列化为 JsonNode 对象
...@@ -332,6 +405,8 @@ public class RpaCore { ...@@ -332,6 +405,8 @@ public class RpaCore {
* @param url 页面 URL * @param url 页面 URL
*/ */
public void visit(String url) { public void visit(String url) {
try {
this.driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(30));
this.driver.get(url); this.driver.get(url);
// 计算浏览器右下角位置 // 计算浏览器右下角位置
var x = this.driver.executeScript("return window.outerWidth - window.innerWidth"); var x = this.driver.executeScript("return window.outerWidth - window.innerWidth");
...@@ -339,6 +414,9 @@ public class RpaCore { ...@@ -339,6 +414,9 @@ public class RpaCore {
if (x instanceof Number pX && y instanceof Number pY) { if (x instanceof Number pX && y instanceof Number pY) {
browserOffset = new Point(pX.doubleValue() * this.scale, pY.doubleValue() * this.scale); browserOffset = new Point(pX.doubleValue() * this.scale, pY.doubleValue() * this.scale);
} }
} catch (org.openqa.selenium.TimeoutException e) {
this.executeJavaScript("window.stop()", Objects.class);
}
} }
/** /**
...@@ -581,31 +659,14 @@ public class RpaCore { ...@@ -581,31 +659,14 @@ public class RpaCore {
""", String.class), Point.class); """, String.class), Point.class);
assert result != null; assert result != null;
var leftTopOffset = new Point( var leftTopOffset = new Point(this.browserOffset.x() + result.x() * this.scale, this.browserOffset.y() + result.y() * this.scale);
this.browserOffset.x() + result.x() * this.scale,
this.browserOffset.y() + result.y() * this.scale var elementRect = JacksonKits.toJsonNode(this.executeJavaScript("return JSON.stringify(arguments[0].getBoundingClientRect())", String.class, element));
);
var lt = new Point((leftTopOffset.x() + this.readFromJsonNode(elementRect, "left")) * this.scale, (leftTopOffset.y() + this.readFromJsonNode(elementRect, "top")) * this.scale);
var elementRect = JacksonKits.toJsonNode( var rt = new Point((leftTopOffset.x() + this.readFromJsonNode(elementRect, "right")) * this.scale, (leftTopOffset.y() + this.readFromJsonNode(elementRect, "top")) * this.scale);
this.executeJavaScript("return JSON.stringify(arguments[0].getBoundingClientRect())", String.class, element) var rb = new Point((leftTopOffset.x() + this.readFromJsonNode(elementRect, "right")) * this.scale, (leftTopOffset.y() + this.readFromJsonNode(elementRect, "bottom")) * this.scale);
); var lb = new Point((leftTopOffset.x() + this.readFromJsonNode(elementRect, "left")) * this.scale, (leftTopOffset.y() + this.readFromJsonNode(elementRect, "bottom")) * this.scale);
var lt = new Point(
(leftTopOffset.x() + this.readFromJsonNode(elementRect, "left")) * this.scale,
(leftTopOffset.y() + this.readFromJsonNode(elementRect, "top")) * this.scale
);
var rt = new Point(
(leftTopOffset.x() + this.readFromJsonNode(elementRect, "right")) * this.scale,
(leftTopOffset.y() + this.readFromJsonNode(elementRect, "top")) * this.scale
);
var rb = new Point(
(leftTopOffset.x() + this.readFromJsonNode(elementRect, "right")) * this.scale,
(leftTopOffset.y() + this.readFromJsonNode(elementRect, "bottom")) * this.scale
);
var lb = new Point(
(leftTopOffset.x() + this.readFromJsonNode(elementRect, "left")) * this.scale,
(leftTopOffset.y() + this.readFromJsonNode(elementRect, "bottom")) * this.scale
);
return new Rectangle(lt, rt, rb, lb); return new Rectangle(lt, rt, rb, lb);
} }
...@@ -820,10 +881,7 @@ public class RpaCore { ...@@ -820,10 +881,7 @@ public class RpaCore {
*/ */
public void moveTo(WebElement element, MoveDirection direction) { public void moveTo(WebElement element, MoveDirection direction) {
var rect = this.sumElementRectangle(element); var rect = this.sumElementRectangle(element);
var point = new Point( var point = new Point((rect.leftTop().x() + rect.rightBottom().x()) / 2, (rect.leftTop().y() + rect.rightBottom().y()) / 2);
(rect.leftTop().x() + rect.rightBottom().x()) / 2,
(rect.leftTop().y() + rect.rightBottom().y()) / 2
);
this.moveTo(point, direction); this.moveTo(point, direction);
} }
...@@ -862,6 +920,36 @@ public class RpaCore { ...@@ -862,6 +920,36 @@ public class RpaCore {
WinApi.dragTo(point.x(), point.y(), duration); WinApi.dragTo(point.x(), point.y(), duration);
} }
/**
* 使用selenium方式拖拽元素一定的偏移距离
* @param dragHandler
* @param xoffset
*/
public void dragCenter(WebElement dragHandler, int xoffset) {
this.resetInputState();
Actions action = new Actions(this.driver);
action.moveToElement(dragHandler).clickAndHold().build().perform();
int currentOffset = 0;
int setp = 10;
while (true) {
action = new Actions(this.driver);
action.moveByOffset(setp, 0).build().perform();
currentOffset += setp;
if (currentOffset >= xoffset) {
break;
}
this.sleep(1);
}
action = new Actions(this.driver);
action.release().build().perform();
}
public void drag(WebElement dragHandler, WebElement dragHandlerContiner){
// Rectangle handlerRect = this.sumElementRectangle(dragHandlerContiner);
int xoffset=dragHandlerContiner.getRect().width;
this.dragCenter(dragHandler,xoffset);
}
/* ------------------------- 辅助方法 ------------------------- */ /* ------------------------- 辅助方法 ------------------------- */
/** /**
...@@ -924,5 +1012,179 @@ public class RpaCore { ...@@ -924,5 +1012,179 @@ public class RpaCore {
WinApi.delay(ms); WinApi.delay(ms);
} }
public boolean isAlertPersent() {
try {
this.driver.switchTo().alert();
return true;
} catch (Exception e) {
return false;
}
}
public String getAlert() {
String currentWindowHandle = this.getCurrentWindowHandle();
Alert alert = this.driver.switchTo().alert();
String text = alert.getText();
alert.accept();
this.switchWindow(currentWindowHandle);
return text;
}
public void acceptAlert() {
String currentWindowHandle = this.getCurrentWindowHandle();
Alert alert = this.driver.switchTo().alert();
alert.accept();
this.switchWindow(currentWindowHandle);
}
public void sendEnterCmd(int offsetMiliSeconds) {
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "driver 已发送 enter");
Date exeDate = new Date(System.currentTimeMillis() + offsetMiliSeconds);
//发送命令
this.heartThreadCmd.put(ENTER, exeDate);
//尝试点击alert
if (this.isAlertPersent()) {
this.acceptAlert();
}
System.out.println(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "driver 已经清空 enter");
this.clearCmd();
}
public void clearCmd() {
this.heartThreadCmd.clear();
}
public Set<String> getWindowHandles() {
try {
return this.driver.getWindowHandles();
} catch (Exception e) {
return null;
}
}
public String getCurrentWindowHandle() {
try {
return this.driver.getWindowHandle();
} catch (Exception e) {
return "";
}
}
public void switchWindow(String nameOrHandle) {
try {
this.driver.switchTo().window(nameOrHandle);
} catch (Exception e) {
throw e;
}
}
private ConcurrentHashMap<String, String> networkMap = new ConcurrentHashMap<>();
public void enableNetWork() {
//开启监听
DevTools devTools = this.driver.getDevTools();
devTools.createSession();
devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
//增加全部的请求
devTools.addListener(Network.responseReceived(), res -> {
try {
networkMap.put(res.getResponse().getUrl(), devTools.send(Network.getResponseBody(res.getRequestId())).getBody());
}
catch (Exception ex){
}
});
}
public String listenNetWorkCenter(String matchUrl, Long timeoutMs) {
try {
Date startTime = new Date();
while (true) {
for (Map.Entry<String, String> item : networkMap.entrySet()) {
if (StringUtils.contains(item.getKey(), matchUrl)) {
return item.getValue();
}
}
this.sleep(10);
if (System.currentTimeMillis() - startTime.getTime() > timeoutMs) {
throw new TimeoutException("listenNetWork time out");
}
}
} finally {
this.closeNetWork();
}
}
private String listenNetWorkCenterExample(String matchUrl, Long timeoutMs) {
// devTools.addListener(Network.responseReceived(),responseReceived -> {
// RequestId requestId = responseReceived.getRequestId();
// Network.GetResponseBodyResponse response = devTools.send(Network.getResponseBody(requestId));
//
// String body = response.getBody();
// System.out.println(body);
// });
// 获取Request信息
// devTools.addListener(Network.requestWillBeSent(), res -> {
// System.out.println("RequestHeaders:" + res.getRequest().getHeaders());
// System.out.println("RequestHeaders:" + res.getRequest().getUrl());
// });
// 获取Response信息
// devTools.addListener(Network.responseReceived(), res -> {
// System.out.println("ResponseHeaders:" + res.getResponse().getHeaders());
// System.out.println("ResponseURL:" + res.getResponse().getUrl());
// });
// xhr MimeType
// 'application/javascript', 'application/x-javascript', 'text/css', 'webp', 'image/png', 'image/gif',
// 'image/jpeg', 'image/x-icon', 'application/octet-stream','xhr'
// if ("xhr".equals(response.getMimeType()))
DevTools devTools = this.driver.getDevTools();
try {
AtomicReference<String> responseBody = new AtomicReference<>("");
// 获取Response响应内容
devTools.addListener(Network.responseReceived(), res -> {
Response response = res.getResponse();
System.out.println("response.getUrl():" + response.getUrl());
if (response.getUrl().contains(matchUrl)) {
if (StringUtils.isBlank(responseBody.get())) {
// 获取network 请求的responseBody
responseBody.set(devTools.send(Network.getResponseBody(res.getRequestId())).getBody());
}
}
});
Date startTime = new Date();
while (true) {
this.sleep(10);
if (StringUtils.isNotBlank(responseBody.get())) {
return responseBody.get();
}
if (System.currentTimeMillis() - startTime.getTime() > timeoutMs) {
throw new TimeoutException("listenNetWork time out");
}
}
} finally {
this.closeNetWork();
}
}
public void closeNetWork() {
try {
this.driver.getDevTools().send(Network.disable());
} catch (Exception e) {
} finally {
this.networkMap.clear();
}
}
public void resetInputState() {
this.driver.resetInputState();
}
} }
...@@ -4,6 +4,7 @@ import com.greatchn.rpa.beans.Button; ...@@ -4,6 +4,7 @@ import com.greatchn.rpa.beans.Button;
import com.greatchn.rpa.beans.Point; import com.greatchn.rpa.beans.Point;
import java.awt.*; import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -144,6 +145,11 @@ public final class WinApi { ...@@ -144,6 +145,11 @@ public final class WinApi {
} }
} }
public static void enter(){
ROBOT.keyPress(KeyEvent.VK_ENTER);
ROBOT.keyRelease(KeyEvent.VK_ENTER);
}
public static void main(String[] args) { public static void main(String[] args) {
mouseMove(0, 0); mouseMove(0, 0);
mouseMove(1000, 1000, 1000); mouseMove(1000, 1000, 1000);
......
...@@ -22,6 +22,12 @@ public class RpaConfig { ...@@ -22,6 +22,12 @@ public class RpaConfig {
private Browser browser; private Browser browser;
private Rpa rpa; private Rpa rpa;
private Double scale; private Double scale;
//新增参数
private boolean useSeleniumDrag;
private boolean networkProxy;
private boolean remoteDebugging;
private int remoteDebuggingPort;
private String remoteDebuggingIP;
/** /**
* 使用默认配置文件加载配置 * 使用默认配置文件加载配置
......
package com.greatchn.yzh; package com.greatchn.yzh;
import cn.hutool.core.date.DateUtil;
import com.greatchn.etax.monitor.Monitor; import com.greatchn.etax.monitor.Monitor;
import com.greatchn.etax.tianjin.Tianjin; import com.greatchn.etax.tianjin.Tianjin;
import com.greatchn.kits.EnvironmentToolkit; import com.greatchn.kits.EnvironmentToolkit;
import com.greatchn.kits.HashKits; import com.greatchn.kits.HashKits;
import com.greatchn.rpa.WinApi;
import com.greatchn.rpa.config.RpaConfig; import com.greatchn.rpa.config.RpaConfig;
import com.greatchn.yzh.db.Db; import com.greatchn.yzh.db.Db;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebElement;
import java.io.File;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* 云账户 RPA 任务处理器 * 云账户 RPA 任务处理器
...@@ -25,21 +36,90 @@ public final class TaskExecutor { ...@@ -25,21 +36,90 @@ public final class TaskExecutor {
private final Tianjin tianjin; private final Tianjin tianjin;
private final Monitor monitor; private final Monitor monitor=null;
private final String instanceID; private final String instanceID;
private final String ip; private final String ip;
public TaskExecutor() { public TaskExecutor() throws InterruptedException {
instanceID = "%s_java_rpa".formatted(HashKits.sha256(EnvironmentToolkit.getMac().getBytes(StandardCharsets.UTF_8))); instanceID = "%s_java_rpa".formatted(HashKits.sha256(EnvironmentToolkit.getMac().getBytes(StandardCharsets.UTF_8)));
ip = EnvironmentToolkit.getLocalIp(); ip = EnvironmentToolkit.getLocalIp();
db = new Db(); db = new Db();
tianjin = new Tianjin(RpaConfig.build("rpa.yaml")); tianjin = new Tianjin(RpaConfig.build("rpa.yaml"));
monitor = new Monitor(); // monitor = new Monitor();
String taxFileNo="91120116MA05TT0A0D";
tianjin.login(taxFileNo, "13516135467", "Badboy1993");
tianjin.login("91120223MA079XXY07", "131026199607185115", "ds111111");
//我要办税
WebElement wybs = tianjin.rpa().findElement(By.xpath(".//a[text()='我要办税']"),10);
tianjin.rpa().click(wybs);
//frame
WebElement iframe = tianjin.rpa().findElement(By.cssSelector("#profile > iframe"), 10);
//税务数字账户
tianjin.rpa().switchToFrame(iframe);
WebElement swsszh = tianjin.rpa().findElement(By.xpath(".//li[@title='税务数字账户']"),10);
tianjin.rpa().click(swsszh);
tianjin.rpa().switchToParent();
//tianjin.rpa().listen("/menuAuth/getMenuAuthSwitch.do",10);
tianjin.rpa().refresh();
System.out.println("已刷新");
//税务数字账户2
WebElement swsszh2 = tianjin.rpa().findElement(By.xpath(".//div[@class='leftPanel-li-div']//span[text()='税务数字账户']"),10);
tianjin.rpa().click(swsszh2);
System.out.println("税务数字账户2点击完毕");
Thread.sleep(10000L);
tianjin.rpa().sendEnterCmd(10000);
while(true) {
//new page
Thread.sleep(1000);
Set<String> windowHandles = tianjin.rpa().getWindowHandles();
System.out.println("windowHandles:"+windowHandles.size());
if (windowHandles.size()>1) {
List<String> collect = windowHandles.stream().collect(Collectors.toList());
tianjin.rpa().switchWindow(collect.get(1));
break;
}
}
tianjin.rpa().visit("https://dppt.tianjin.chinatax.gov.cn:8443/invoice-query/invoice-query?ruuid="+System.currentTimeMillis());
Thread.sleep(10000L);
tianjin.rpa().sendEnterCmd(10000);
//发票查询统计
// WebElement fpcxtj = tianjin.rpa().findElement(By.xpath(".//div[@class='app_name__bold'][text()='发票查询统计']"),10);
// tianjin.rpa().click(fpcxtj);
//全量发票查询
// WebElement qlfpcx = tianjin.rpa().findElement(By.xpath(".//div[@class='g-card-menu-item__title'][text()='全量发票查询']"));
// tianjin.rpa().click(qlfpcx);
// tianjin.rpa().visit("https://dppt.tianjin.chinatax.gov.cn:8443/invoice-query/invoice-query?"+System.currentTimeMillis());
tianjin.rpa().newHar();
WebElement queryButton = tianjin.rpa().findElement(By.xpath(".//span[text()='查询']"), 60);
tianjin.rpa().click(queryButton);
tianjin.rpa().listen("/qlfpcx/v1/queryFpjeseHj",10);
File srcFile = tianjin.rpa().driver().getScreenshotAs(OutputType.FILE);
srcFile.renameTo(new File("./files/全电_%s_%s.jpg".formatted(taxFileNo, DateUtil.format(new Date(),"yyyy_MM_dd HH_mm_ss"))));
System.out.println("finish");
// tianjin.queryDutyPaidProof("91120223MA079XXY07", "131026199607185115", "ds111111","510211201000000362315","2019-01-01", "2019-12-31"); // tianjin.queryDutyPaidProof("91120223MA079XXY07", "131026199607185115", "ds111111","510211201000000362315","2019-01-01", "2019-12-31");
// 心跳 // 心跳
{ {
......
...@@ -3,13 +3,27 @@ selenium: ...@@ -3,13 +3,27 @@ selenium:
browser: browser:
chrome: /Google/Chrome/Application/chrome.exe chrome: /Google/Chrome/Application/chrome.exe
rpa: rpa:
#Mobo代理
proxy: proxy:
enable: true enable: false
port: 30001 port: 30001
cookies: cookies:
clean: true clean: true
fullScreen: false fullScreen: false
autoScroll: true autoScroll: true
autoCreate: true autoCreate: true
simulate: true simulate: false
#新增参数
useSeleniumDrag: true
#chrome的network,不可以与Mobo代理同时打开
networkProxy: true
#是否使用selenium来自动启动浏览器
remoteDebugging: true
remoteDebuggingPort: 9222
remoteDebuggingIP: "127.0.0.1"
scale: 1.00 scale: 1.00
import com.greatchn.rpa.RpaCore;
import com.greatchn.rpa.config.RpaConfig;
import com.greatchn.yzh.TaskExecutor;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
public class DriverTest {
public static void main(String[] args) throws InterruptedException {
var config = RpaConfig.build();
RpaCore rpa=new RpaCore(config);
rpa.visit("chrome://version/");
//network
//rpa.enableNetWork();
rpa.visit("https://www.baidu.com");
System.out.println(rpa.listenNetWorkCenter("sugrec", 10000L));
//drag
rpa.visit("https://tpass.tianjin.chinatax.gov.cn:8443/#/login?redirect_uri=https%3A%2F%2Fetax.tianjin.chinatax.gov.cn%2Foutsider%2Fsso%2FmainPage.do&client_id=x3ef652ax3294xz6beefnf5zadbf66cc&response_type=code&state=test");
var dragHandler = rpa.findElement(By.cssSelector(".handler.animate"), 1);
WebElement continer=rpa.findElement(dragHandler,By.xpath("./.."));
System.out.println(continer.getText());
rpa.drag(dragHandler,continer);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment