Code Online Debugging!!!

This commit is contained in:
naibo 2023-12-10 14:52:31 +08:00
parent 32f357a866
commit de547cac11
25 changed files with 3759 additions and 217 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
// Modules to control application life and create native browser window
const {app, BrowserWindow, dialog, ipcMain, screen, session} = require('electron');
app.commandLine.appendSwitch("--disable-http-cache");
const {Builder, By, Key, until} = require("selenium-webdriver");
const {Builder, By, Key, until, Select, StaleElementReferenceException} = require("selenium-webdriver");
const chrome = require('selenium-webdriver/chrome');
const {ServiceBuilder} = require('selenium-webdriver/chrome');
const {rootCertificates} = require('tls');
@ -16,14 +16,14 @@ const util = require('util');
let config = fs.readFileSync(path.join(task_server.getDir(), `config.json`), 'utf8');
config = JSON.parse(config);
if(config.debug){
if (config.debug) {
let logPath = 'info.log'
let logFile = fs.createWriteStream(logPath, { flags: 'a' })
console.log = function() {
let logFile = fs.createWriteStream(logPath, {flags: 'a'})
console.log = function () {
logFile.write(util.format.apply(null, arguments) + '\n')
process.stdout.write(util.format.apply(null, arguments) + '\n')
}
console.error = function() {
console.error = function () {
logFile.write(util.format.apply(null, arguments) + '\n')
process.stderr.write(util.format.apply(null, arguments) + '\n')
}
@ -39,7 +39,7 @@ let chromeBinaryPath = "";
let execute_path = "";
console.log(process.arch);
exec(`wmic os get Caption`, function(error, stdout, stderr) {
exec(`wmic os get Caption`, function (error, stdout, stderr) {
if (error) {
console.error(`执行的错误: ${error}`);
return;
@ -120,7 +120,7 @@ function createWindow() {
// and load the index.html of the app.
// mainWindow.loadFile('src/index.html');
mainWindow.loadURL(server_address + '/index.html?user_data_folder=' + config.user_data_folder+"&copyright=" + config.copyright, { extraHeaders: 'pragma: no-cache\n' });
mainWindow.loadURL(server_address + '/index.html?user_data_folder=' + config.user_data_folder + "&copyright=" + config.copyright, {extraHeaders: 'pragma: no-cache\n'});
// 隐藏菜单栏
const {Menu} = require('electron');
Menu.setApplicationMenu(null);
@ -135,6 +135,134 @@ function createWindow() {
}
async function findElementRecursive(driver, by, value, frames) {
for (const frame of frames) {
try {
// Try to switch to the frame
try {
await driver.switchTo().frame(frame);
} catch (error) {
if (error.name.indexOf('StaleElement') >= 0) {
// If the frame is stale, switch to the parent frame and then retry switching to the frame
await driver.switchTo().parentFrame();
await driver.switchTo().frame(frame);
} else {
// If it is another exception rethrow it
throw error;
}
}
let element;
try {
// Attempt to find the element in this frame
element = await driver.findElement(by(value));
return element;
} catch (error) {
if (error.name.indexOf('NoSuchElement') >= 0) {
// The element was not found in this frame, recurse into nested iframes
const nestedFrames = await driver.findElements(By.tagName("iframe"));
if (nestedFrames.length > 0) {
element = await findElementRecursive(driver, by, value, nestedFrames);
if (element) {
return element;
}
}
} else {
// If it is another exception, log it
console.error(`Exception while processing frame: ${error}`);
}
}
} catch (error) {
console.error(`Exception while processing frame: ${error}`);
}
}
throw new Error(`Element ${value} not found in any frame or iframe`);
}
async function findElement(driver, by, value, iframe = false) {
// Switch back to the main document
await driver.switchTo().defaultContent();
if (iframe) {
const frames = await driver.findElements(By.tagName("iframe"));
if (frames.length === 0) {
throw new Error(`No iframes found in the current page while searching for ${value}`);
}
const element = await findElementRecursive(driver, by, value, frames);
return element;
} else {
// Find element in the main document as normal
let element = await driver.findElement(by(value));
return element;
}
}
async function findElementAcrossAllWindows(msg) {
let handles = await driver.getAllWindowHandles();
// console.log("handles", handles);
let content_handle = current_handle;
let id = -1;
try {
id = msg.message.id;
} catch {
id = msg.id;
}
if (id == -1) { //如果是-1从当前窗口开始搜索
content_handle = current_handle;
} else {
content_handle = handle_pairs[id];
}
// console.log(msg.message.id, content_handle);
let order = [...handles.filter(handle => handle != current_handle && handle != content_handle), current_handle, content_handle]; //搜索顺序
let len = order.length;
let element = null;
let iframe = false;
try {
iframe = msg.message.iframe;
} catch {
iframe = msg.iframe;
}
if (iframe) {
notify_browser("在IFrame中执行操作可能需要较长时间请耐心等待。", "Executing operations in IFrame may take a long time, please wait patiently.", "info");
}
let xpath = "";
try {
xpath = msg.message.xpath;
} catch {
xpath = msg.xpath;
}
let notify = false;
while (true) {
// console.log("handles");
try {
let h = order[len - 1];
console.log("current_handle", current_handle);
if (h != null && handles.includes(h)) {
await driver.switchTo().window(h);
current_handle = h;
console.log("switch to handle: ", h);
}
element = await findElement(driver, By.xpath, xpath, iframe);
break;
} catch (error) {
console.log("len", len);
len = len - 1;
if (!notify) {
notify = true;
notify_browser("正在尝试在其他窗口中查找元素,请耐心等待。", "Trying to find elements in other windows, please wait patiently.", "info");
}
if (len == 0) {
break;
}
}
}
if (element == null) {
notify_browser("无法找到元素请检查xpath是否正确" + xpath, "Cannot find the element, please check if the xpath is correct: " + xpath, "warning");
}
return element;
}
async function beginInvoke(msg, ws) {
if (msg.type == 1) {
if (msg.message.id != -1) {
@ -145,13 +273,13 @@ async function beginInvoke(msg, ws) {
url = server_address + `/taskGrid/FlowChart.html?id=${msg.message.id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address;
}
console.log(url);
flowchart_window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
flowchart_window.loadURL(url, {extraHeaders: 'pragma: no-cache\n'});
}
mainWindow.hide();
// Prints the currently focused window bounds.
// This method has to be called on macOS before changing the window's bounds, otherwise it will throw an error.
// It will prompt an accessibility permission request dialog, if needed.
if(process.platform != "linux" && process.platform != "darwin"){
if (process.platform != "linux" && process.platform != "darwin") {
const {windowManager} = require("node-window-manager");
const window = windowManager.getActiveWindow();
console.log(window);
@ -169,74 +297,15 @@ async function beginInvoke(msg, ws) {
// 键盘输入事件
// const robot = require("@jitsi/robotjs");
let keyInfo = msg.message.keyboardStr;
let handles = await driver.getAllWindowHandles();
console.log("handles", handles);
let exit = false;
let content_handle = handle_pairs[msg.message.id];
console.log(msg.message.id, content_handle);
let order = [...handles.filter(handle => handle != current_handle && handle != content_handle), current_handle, content_handle]; //搜索顺序
let len = order.length;
while (true) {
// console.log("handles");
try{
let iframe = msg.message.iframe;
let enter = false;
if (/<enter>/i.test(keyInfo)) {
keyInfo = keyInfo.replace(/<enter>/gi, '');
enter = true;
}
let h = order[len - 1];
console.log("current_handle", current_handle);
if(h != null && handles.includes(h)){
await driver.switchTo().window(h);
current_handle = h;
console.log("switch to handle: ", h);
}
// await driver.executeScript("window.stop();");
// console.log("executeScript");
if(!iframe){
let element = await driver.findElement(By.xpath(msg.message.xpath));
console.log("Find Element at handle: ", current_handle);
// 使用正则表达式匹配 '<enter>',不论大小写
await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
if(enter){
await element.sendKeys(Key.ENTER);
}
console.log("send key");
break;
} else {
let iframes = await driver.findElements(By.tagName('iframe'));
// 遍历所有的 iframe 并点击里面的元素
for(let i = 0; i < iframes.length; i++) {
let iframe = iframes[i];
// 切换到 iframe
await driver.switchTo().frame(iframe);
// 在 iframe 中查找并点击元素
let element;
try {
element = await driver.findElement(By.xpath(msg.message.xpath));
} catch (error) {
console.log('No such element found in the iframe');
}
if (element) {
await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
if(enter){
await element.sendKeys(Key.ENTER);
}
}
// 完成操作后切回主文档
await driver.switchTo().defaultContent();
}
break;
}
} catch (error) {
console.log("len", len);
len = len - 1;
if (len == 0) {
break;
}
}
let enter = false;
if (/<enter>/i.test(keyInfo)) {
keyInfo = keyInfo.replace(/<enter>/gi, '');
enter = true;
}
let element = await findElementAcrossAllWindows(msg);
await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
if (enter) {
await element.sendKeys(Key.ENTER);
}
} else if (msg.type == 3) {
try {
@ -245,76 +314,144 @@ async function beginInvoke(msg, ws) {
let message = JSON.parse(msg.message.pipe);
let type = message.type;
console.log("FROM Browser: ", message);
console.log("Iframe:", message.iframe);
if(type.indexOf("Click")>=0){
// 鼠标点击事件
let iframe = message.iframe;
let handles = await driver.getAllWindowHandles();
console.log("handles", handles);
let exit = false;
let content_handle = handle_pairs[message.id];
console.log(message.id, content_handle);
let order = [...handles.filter(handle => handle != current_handle && handle != content_handle), current_handle, content_handle]; //搜索顺序
let len = order.length;
while(true) {
try{
let h = order[len - 1];
console.log("current_handle", current_handle);
if(h != null && handles.includes(h)){
await driver.switchTo().window(h); //执行失败会抛出异常
current_handle = h;
console.log("switch to handle: ", h);
}
//下面是找到窗口的情况下
if(!iframe){
let element = await driver.findElement(By.xpath(message.xpath));
await element.click();
break;
} else {
let iframes = await driver.findElements(By.tagName('iframe'));
// 遍历所有的 iframe 并点击里面的元素
for(let i = 0; i < iframes.length; i++) {
let iframe = iframes[i];
// 切换到 iframe
await driver.switchTo().frame(iframe);
// 在 iframe 中查找并点击元素
let element;
try {
element = await driver.findElement(By.xpath(message.xpath));
} catch (error) {
console.log('No such element found in the iframe');
}
if (element) {
await element.click();
}
// 完成操作后切回主文档
await driver.switchTo().defaultContent();
}
break;
}
} catch (error) {
console.log("len", len); //如果没有找到元素,就切换到下一个窗口
len = len - 1;
if (len == 0) {
break;
}
}
if (type.indexOf("Click") >= 0 || type.indexOf("Move") >= 0) {
let element = await findElementAcrossAllWindows(message);
if (type.indexOf("Click") >= 0) {
await click_element(element);
} else if (type.indexOf("Move") >= 0) {
await driver.actions().move({origin: element}).perform();
}
}
} else {
socket_window.send(msg.message.pipe);
for(let i in allWindowSockets){
try{
allWindowSockets[i].send(msg.message.pipe);
} catch {
console.log("Cannot send to socket with id: ", allWindowScoketNames[i]);
}
}
send_message_to_browser(msg.message.pipe);
console.log("FROM Flowchart: ", JSON.parse(msg.message.pipe));
}
} catch (e) {
console.log(e);
}
} else if (msg.type == 4) { //试运行功能
if (socket_window == null) {
notify_flowchart("试运行功能只能在设计任务阶段Chrome浏览器打开时使用", "The trial run function can only be used when designing tasks and opening in Chrome browser!", "error");
} else {
let node = JSON.parse(msg.message.node);
notify_browser("正在试运行操作:" + node.title, "Trying to run the operation: " + node.title, "info");
let option = node.option;
let parameters = node.parameters;
let beforeJS = "";
let beforeJSWaitTime = 0;
let afterJS = "";
let afterJSWaitTime = 0;
try {
beforeJS = parameters.beforeJS;
beforeJSWaitTime = parameters.beforeJSWaitTime;
afterJS = parameters.afterJS;
afterJSWaitTime = parameters.afterJSWaitTime;
} catch (e) {
console.log(e);
}
if (option == 1) {
let url = parameters.links.split("\n")[0].trim();
if (parameters.useLoop) {
let parent_node = JSON.parse(msg.message.parentNode);
url = parent_node["parameters"]["textList"].split("\n")[0];
}
await driver.get(url);
} else if (option == 2 || option == 7) { //点击事件
let elementInfo = {"iframe": parameters.iframe, "xpath": parameters.xpath, "id": -1};
if (parameters.useLoop) {
let parent_node = JSON.parse(msg.message.parentNode);
let parent_xpath = parent_node.parameters.xpath;
elementInfo.xpath = parent_xpath + elementInfo.xpath;
}
let element = await findElementAcrossAllWindows(elementInfo);
if (beforeJS != "") {
await driver.executeScript(beforeJS, element);
await new Promise(resolve => setTimeout(resolve, beforeJSWaitTime));
}
if (option == 2) {
await click_element(element);
} else if (option == 7) {
await driver.actions().move({origin: element}).perform();
}
if (afterJS != "") {
await driver.executeScript(afterJS, element);
await new Promise(resolve => setTimeout(resolve, afterJSWaitTime));
}
send_message_to_browser(JSON.stringify({"type": "cancelSelection"}));
} else if (option == 4) { //键盘输入事件
let elementInfo = {"iframe": parameters.iframe, "xpath": parameters.xpath, "id": -1};
let value = node.parameters.value;
if (node.parameters.useLoop) {
let parent_node = JSON.parse(msg.message.parentNode);
value = parent_node["parameters"]["textList"].split("\n")[0];
let index = node.parameters.index;
if (index > 0) {
value = value.split("~")[index - 1];
}
}
let keyInfo = value
let enter = false;
if (/<enter>/i.test(keyInfo)) {
keyInfo = keyInfo.replace(/<enter>/gi, '');
enter = true;
}
let element = await findElementAcrossAllWindows(elementInfo);
if (beforeJS != "") {
await driver.executeScript(beforeJS, element);
await new Promise(resolve => setTimeout(resolve, beforeJSWaitTime));
}
await element.sendKeys(Key.HOME, Key.chord(Key.SHIFT, Key.END), keyInfo);
if (enter) {
await element.sendKeys(Key.ENTER);
}
if (afterJS != "") {
await driver.executeScript(afterJS, element);
await new Promise(resolve => setTimeout(resolve, afterJSWaitTime));
}
} else if (option == 5) { //自定义操作的JS代码
let code = parameters.code;
await driver.executeScript(code);
} else if (option == 6) { //切换下拉选项
let optionMode = parseInt(parameters.optionMode);
let optionValue = parameters.optionValue;
if (node.parameters.useLoop) {
let parent_node = JSON.parse(msg.message.parentNode);
optionValue = parent_node["parameters"]["textList"].split("\n")[0];
let index = node.parameters.index;
if (index > 0) {
optionValue = optionValue.split("~")[index - 1];
}
}
let elementInfo = {"iframe": parameters.iframe, "xpath": parameters.xpath, "id": -1};
let element = await findElementAcrossAllWindows(elementInfo);
if (beforeJS != "") {
await driver.executeScript(beforeJS, element);
await new Promise(resolve => setTimeout(resolve, beforeJSWaitTime));
}
let dropdown = new Select(element);
// Interacting with dropdown element based on optionMode
switch (optionMode) {
case 0: //切换到下一个选项
let script = "var options = arguments[0].options;for (var i = 0; i < options.length; i++) {if (options[i].selected) {options[i].selected = false;if (i == options.length - 1) {options[0].selected = true;} else {options[i + 1].selected = true;}break;}}";
await driver.executeScript(script, element);
break;
case 1:
await dropdown.selectByIndex(parseInt(optionValue));
break;
case 2:
await dropdown.selectByValue(optionValue);
break;
case 3:
await dropdown.selectByVisibleText(optionValue);
break;
default:
throw new Error('Invalid option mode');
}
}
}
} else if (msg.type == 8) { //展示元素功能
} else if (msg.type == 5) {
let child = require('child_process').execFile;
// 参数顺序: 1. task id 2. server address 3. saved_file_name 4. "remote" or "local" 5. user_data_folder
@ -330,7 +467,7 @@ async function beginInvoke(msg, ws) {
config.absolute_user_data_folder = user_data_folder_path;
fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
}
if(msg.message.mysql_config_path != "-1"){
if (msg.message.mysql_config_path != "-1") {
config.mysql_config_path = msg.message.mysql_config_path;
}
fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
@ -345,21 +482,24 @@ async function beginInvoke(msg, ws) {
console.log(data.toString());
});
}
ws.send(JSON.stringify({"config_folder": task_server.getDir() + "/", "easyspider_location": task_server.getEasySpiderLocation()}));
ws.send(JSON.stringify({
"config_folder": task_server.getDir() + "/",
"easyspider_location": task_server.getEasySpiderLocation()
}));
} else if (msg.type == 6) {
try{
try {
flowchart_window.openDevTools();
} catch {
console.log("open devtools error");
}
try{
try {
invoke_window.openDevTools();
} catch {
console.log("open devtools error");
}
} else if (msg.type == 7) {
// 获得当前页面Cookies
try{
try {
let cookies = await driver.manage().getCookies();
console.log("Cookies: ", cookies);
let cookiesText = cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('\n');
@ -370,6 +510,34 @@ async function beginInvoke(msg, ws) {
}
}
async function click_element(element) {
try {
await element.click();
} catch (e) {
console.log(e);
await driver.executeScript("arguments[0].click();", element);
}
}
function notify_flowchart(msg_zh, msg_en, level = "info") {
socket_flowchart.send(JSON.stringify({"type": "notify", "level": level, "msg_zh": msg_zh, "msg_en": msg_en}));
}
function notify_browser(msg_zh, msg_en, level = "info") {
send_message_to_browser(JSON.stringify({"type": "notify", "level": level, "msg_zh": msg_zh, "msg_en": msg_en}));
}
function send_message_to_browser(message) {
socket_window.send(message);
for (let i in allWindowSockets) {
try {
allWindowSockets[i].send(message);
} catch {
console.log("Cannot send to socket with id: ", allWindowScoketNames[i]);
}
}
}
const WebSocket = require('ws');
const {all} = require("express/lib/application");
let wss = new WebSocket.Server({port: websocket_port});
@ -381,41 +549,48 @@ wss.on('connection', function (ws) {
if (msg.type == 0) {
if (msg.message.id == 0) {
socket_window = ws;
// socket_window.on('close', function (event) {
// socket_window = null;
// console.log("socket_window closed");
// });
console.log("set socket_window")
} else if (msg.message.id == 1) {
socket_start = ws;
console.log("set socket_start")
} else if (msg.message.id == 2) {
socket_flowchart = ws;
// socket_flowchart.on('close', function (event) {
// socket_flowchart = null;
// console.log("socket_flowchart closed");
// });
console.log("set socket_flowchart");
} else { //其他的ID是用来标识不同的浏览器标签页的
await new Promise(resolve => setTimeout(resolve, 2300));
let handles = await driver.getAllWindowHandles();
if(arrayDifference(handles, old_handles).length > 0){
if (arrayDifference(handles, old_handles).length > 0) {
old_handles = handles;
current_handle = handles[handles.length - 1];
console.log("New tab opened, change current_handle to: ", current_handle);
}
handle_pairs[msg.message.id] = current_handle;
console.log("Set handle_pair for id: ", msg.message.id, " to ", current_handle, ", title is: ", msg.message.title);
socket_flowchart.send(JSON.stringify({"type": "title", "data": {"title":msg.message.title}}));
socket_flowchart.send(JSON.stringify({"type": "title", "data": {"title": msg.message.title}}));
allWindowSockets.push(ws);
allWindowScoketNames.push(msg.message.id);
// console.log("handle_pairs: ", handle_pairs);
}
} else if (msg.type == 10) {
let leave_handle = handle_pairs[msg.message.id];
if (leave_handle!=null && leave_handle!=undefined && leave_handle!="")
{
if (leave_handle != null && leave_handle != undefined && leave_handle != "") {
await driver.switchTo().window(leave_handle);
console.log("Switch to handle: ", leave_handle);
current_handle = leave_handle;
}
}
else {
} else {
await beginInvoke(msg, ws);
}
});
});
console.log(process.platform);
@ -461,7 +636,7 @@ async function runBrowser(lang = "en", user_data_folder = '', mobile = false) {
source: stealth,
});
try {
if(mobile){
if (mobile) {
await driver.get(server_address + "/taskGrid/taskList.html?wsport=" + websocket_port + "&backEndAddressServiceWrapper=" + server_address + "&mobile=1&lang=" + lang);
} else {
await driver.get(server_address + "/taskGrid/taskList.html?wsport=" + websocket_port + "&backEndAddressServiceWrapper=" + server_address + "&lang=" + lang);
@ -493,11 +668,11 @@ function handleOpenBrowser(event, lang = "en", user_data_folder = "", mobile = f
if (lang == "en") {
url = server_address + `/taskGrid/FlowChart.html?id=${id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address + "&mobile=" + mobile.toString();
} else if (lang == "zh") {
url = server_address + `/taskGrid/FlowChart_CN.html?id=${id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address+ "&mobile=" + mobile.toString();
url = server_address + `/taskGrid/FlowChart_CN.html?id=${id}&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address + "&mobile=" + mobile.toString();
}
// and load the index.html of the app.
flowchart_window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
if(process.platform != "darwin"){
flowchart_window.loadURL(url, {extraHeaders: 'pragma: no-cache\n'});
if (process.platform != "darwin") {
flowchart_window.hide();
}
flowchart_window.on('close', function (event) {
@ -516,7 +691,7 @@ function handleOpenInvoke(event, lang = "en") {
url = server_address + `/taskGrid/taskList.html?type=1&wsport=${websocket_port}&backEndAddressServiceWrapper=` + server_address + "&lang=zh";
}
// and load the index.html of the app.
invoke_window.loadURL(url, { extraHeaders: 'pragma: no-cache\n' });
invoke_window.loadURL(url, {extraHeaders: 'pragma: no-cache\n'});
invoke_window.maximize();
mainWindow.hide();
invoke_window.on('close', function (event) {
@ -530,7 +705,7 @@ function handleOpenInvoke(event, lang = "en") {
app.whenReady().then(() => {
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
details.requestHeaders['Accept-Language'] = 'zh'
callback({ cancel: false, requestHeaders: details.requestHeaders })
callback({cancel: false, requestHeaders: details.requestHeaders})
})
ipcMain.on('start-design', handleOpenBrowser);
ipcMain.on('start-invoke', handleOpenInvoke);

View File

@ -16,13 +16,13 @@
<body>
<div id="tip" class="alert alert-success alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> Hint: Save Successfully!
</div>
<div id="tipError" class="alert alert-danger alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="error_message">提示保存名不符合MySQL表名规范请重试</span>
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="tip_message">Tip: Save successful!</span>
</div>
<div id="tipInfo" class="alert alert-info alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="info_message">提示:您加载的任务版本不是最新版,可能出现兼容性问题。</span>
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="info_message">Tip: The task version you loaded is not the latest, which may cause compatibility issues.</span>
</div>
<div id="tipError" class="alert alert-danger alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="error_message">Tip: The save name does not conform to MySQL table naming conventions, please try again!</span>
</div>
<div id="navigator">
<nav aria-label="breadcrumb" v-if="type==1">
@ -559,7 +559,7 @@ If the expression returns a value greater than 0 or evaluates to True, the loop
<div v-if='parseInt(loopType) == 0'>
<label>Maximum number of loop iterations (0 represents an infinite loop until no more elements are found or no changes in page content are detected):</label>
<input onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["exitCount"]'></input>
<label>Exit the loop when the content of the following page element does not change (only works when loop iterations are set to 0):</label>
<label>Exit the loop when the content of the following elements on the page does not change (effective when the count is 0. If it is a multi-layer nested iframe, it is recommended to write an XPath for an element that only exists within the iframe page you want to extract, such as /html/body/div[@class='LeftSide_menu']):</label>
<input onkeydown="inputDelete(event)" required class="form-control" type="text" v-model='nowNode["parameters"]["exitElement"]'></input>
</div>

View File

@ -382,6 +382,24 @@ function elementClick(e) {
e.stopPropagation(); //防止冒泡
}
function elementDblClick(e) {
try {
let nodeType = app._data.nowNode["option"]
if (nodeType >= 8) {
showInfo(LANG("试运行功能不适用于循环和条件分支操作。", "The trial run function is not applicable to loop and condition branch operations."))
} else {
if(nodeType == 5 && app._data.nowNode["parameters"]["codeMode"] != 0){
showInfo(LANG("试运行自定义操作功能只适用于执行JavaScript操作。", "The trial run custom action function is only applicable to run JavaScript operation."))
} else {
trailRun(app._data.nowNode);
}
}
} catch (e) {
showError(LANG("试运行功能只能在设计任务阶段Chrome浏览器打开时使用", "The trial run function can only be used when designing tasks and opening in Chrome browser!"));
}
e.stopPropagation(); //防止冒泡
}
//箭头点击事件
function arrowClick(e) {
if (option != 0) {
@ -495,12 +513,11 @@ function toolBoxKernel(e, para = null) {
if (str == "") {
title += LANG("元素", "Element");
} else {
let lang = detectLang(str);
if (lang == 1) { //中文
if(window.location.href.indexOf("_CN") != -1){
if (str.length > l) {
str = str.substring(0, l) + "...";
}
} else { //英文
} else {
if (str.length > l + 7) {
str = str.substring(0, l + 7) + "...";
}
@ -643,6 +660,8 @@ function bindEvents() {
rule.addEventListener('mousedown', elementMousedown);
rule.removeEventListener('click', elementClick);
rule.addEventListener('click', elementClick);
rule.removeEventListener('dblclick', elementDblClick);
rule.addEventListener('dblclick', elementDblClick);
rule.removeEventListener('dragend', elementDragEnd);
rule.addEventListener('dragend', elementDragEnd);
}
@ -749,7 +768,7 @@ document.getElementById("flowchart_graph").oncontextmenu = function (e) {
// 创建一个包含删除选项的右键菜单
let contextMenu = document.createElement("div");
contextMenu.id = "contextMenu";
contextMenu.innerHTML = `<div>${LANG("试运行", "Test Run")}</div>
contextMenu.innerHTML = `<div>${LANG("试运行", "Trial Run")}</div>
<div>${LANG("复制元素", "Copy Element")}</div>
<div>${LANG("剪切元素", "Move Element")}</div>
<div>${LANG("删除元素(双击)", "Delete Element (Double Click)")}</div>`;
@ -802,7 +821,8 @@ document.getElementById("flowchart_graph").oncontextmenu = function (e) {
// Add Test Run functionality
contextMenu.children[0].addEventListener('click', function () {
elementDblClick(e);
contextMenu.remove(); // Remove the context menu
});
// Add copy functionality

View File

@ -16,14 +16,14 @@
<body>
<div id="tip" class="alert alert-success alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> 提示:保存成功!
</div>
<div id="tipError" class="alert alert-danger alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="error_message">提示保存名不符合MySQL表名规范请重试</span>
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="tip_message">提示:保存成功!</span>
</div>
<div id="tipInfo" class="alert alert-info alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="info_message">提示:您加载的任务版本不是最新版,可能出现兼容性问题。</span>
</div>
<div id="tipError" class="alert alert-danger alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
<button type="button" class="close" data-dismiss="alert">&times;</button> <span id="error_message">提示保存名不符合MySQL表名规范请重试</span>
</div>
<div id="navigator">
<nav aria-label="breadcrumb" v-if="type==1">
<ol class="breadcrumb" style="padding-left:23px;padding-bottom: 0;margin-bottom:0;background-color: white">
@ -559,7 +559,7 @@ print(emotlib.emoji()) # 使用其中的函数。
<div v-if='parseInt(loopType) == 0'>
<label>最多执行循环次数0代表无限循环直到找不到元素或检测不到页面元素内容变化为止</label>
<input onkeydown="inputDelete(event)" required class="form-control" type="number" v-model.number='nowNode["parameters"]["exitCount"]'></input>
<label>检测页面以下元素内容不变化时退出循环次数为0时生效</label>
<label>检测页面以下元素内容不变化时退出循环次数为0时生效如果是多层嵌套iframe建议写一个只有要提取的iframe页面内才有的元素的XPath如/html/body/div[@class='LeftSide_menu']</label>
<input onkeydown="inputDelete(event)" required class="form-control" type="text" v-model='nowNode["parameters"]["exitElement"]'></input>
</div>

View File

@ -33,6 +33,14 @@ ws.onmessage = function(evt) {
$("#serviceName").val(evt.data.title);
}
old_title = evt.data.title;
} else if (evt["type"] == "notify") {
if (evt["level"] == "success") {
showSuccess(LANG(evt["msg_zh"], evt["msg_en"]));
} else if(evt["level"] == "info"){
showInfo(LANG(evt["msg_zh"], evt["msg_en"]));
} else if(evt["level"] == "error"){
showError(LANG(evt["msg_zh"], evt["msg_en"]));
}
} else {
handleAddElement(evt); //处理增加元素操作
}
@ -130,11 +138,21 @@ function notifyParameterNum(num) {
let message = {
type: 3, //消息类型3代表元素增加事件
from: 1, //0代表从浏览器到流程图1代表从流程图到浏览器
message: { "pipe": JSON.stringify({ "type": 0, "value": parameterNum }) } // {}全选{BS}退格
message: { "pipe": JSON.stringify({ "type": "update_parameter_num", "value": parameterNum }) } // {}全选{BS}退格
};
ws.send(JSON.stringify(message));
}
function trailRun(node){
let message = {
type: 4, //消息类型4代表试运行事件
from: 1, //0代表从浏览器到流程图1代表从流程图到浏览器
message: { "node": JSON.stringify(node), "parentNode": JSON.stringify(nodeList[actionSequence[node["parentId"]]])}
};
ws.send(JSON.stringify(message));
console.log(message);
}
// 流程图元素点击后的处理逻辑注意在FlowChart_CN.js中watch的那些数据的加载都需要在这里执行
function handleElement() {
@ -325,6 +343,20 @@ function modifyParameters(t, para) {
}
}
function showSuccess(msg, time=4000) {
$("#tip").text(msg);
$("#tip").slideDown(); //提示框
let fadeout = setTimeout(function() {
$("#tip").slideUp();
}, time);
}
function showInfo(msg, time=4000) {
$("#info_message").text(msg);
$("#tipInfo").slideDown(); //提示框
let fadeout = setTimeout(function() {
$("#tipInfo").slideUp();
}, time);
}
function showError(msg, time=4000) {
$("#error_message").text(msg);
$("#tipError").slideDown(); //提示框
@ -333,13 +365,6 @@ function showError(msg, time=4000) {
}, time);
}
function showInfo(msg, time=4000) {
$("#info_message").text(msg);
$("#tipInfo").slideDown(); //提示框
let fadeout = setTimeout(function() {
$("#tipInfo").slideUp();
}, time);
}
//点击确定按钮时的处理
$("#confirm").mousedown(updateUI);
@ -525,10 +550,7 @@ function saveService(type) {
function(result) { $("#serviceId").val(parseInt(result)) });
// alert("保存成功!");
$('#myModal').modal('hide');
$("#tip").slideDown(); //提示框
let fadeout = setTimeout(function() {
$("#tip").slideUp();
}, 2000);
showSuccess(LANG("保存成功!","Save successfully!"));
// }
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

807
ElectronJS/tasks/248.json Normal file
View File

@ -0,0 +1,807 @@
{
"id": 248,
"name": "中国地震台网——历史查询",
"url": "https://www.ceic.ac.cn/history",
"links": "https://www.ceic.ac.cn/history",
"create_time": "",
"update_time": "12/10/2023, 9:14:40 AM",
"version": "0.6.0",
"saveThreshold": 10,
"quitWaitTime": 60,
"environment": 0,
"maximizeWindow": 0,
"maxViewLength": 15,
"recordLog": 1,
"outputFormat": "xlsx",
"saveName": "current_time",
"inputExcel": "",
"startFromExit": 0,
"pauseKey": "p",
"containJudge": false,
"desc": "https://www.ceic.ac.cn/history",
"inputParameters": [
{
"id": 0,
"name": "urlList_0",
"nodeId": 1,
"nodeName": "打开网页",
"value": "https://www.ceic.ac.cn/history",
"desc": "要采集的网址列表,多行以\\n分开",
"type": "text",
"exampleValue": "https://www.ceic.ac.cn/history"
},
{
"id": 1,
"name": "inputText_1",
"nodeName": "输入文字",
"nodeId": 2,
"desc": "要输入的文本,如京东搜索框输入:电脑",
"type": "text",
"exampleValue": "12",
"value": "12"
},
{
"id": 2,
"name": "loopTimes_循环点击单个元素_2",
"nodeId": 4,
"nodeName": "循环点击单个元素",
"desc": "循环循环点击单个元素执行的次数0代表无限循环",
"type": "int",
"exampleValue": 0,
"value": 0
}
],
"outputParameters": [
{
"id": 0,
"name": "参数1_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "3.3"
},
{
"id": 1,
"name": "参数2_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "2023-11-1817:48:35"
},
{
"id": 2,
"name": "参数3_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "36.55"
},
{
"id": 3,
"name": "参数4_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "106.31"
},
{
"id": 4,
"name": "参数5_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "15"
},
{
"id": 5,
"name": "参数6_链接文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "宁夏中卫市海原县"
},
{
"id": 6,
"name": "参数7_链接地址",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "https://news.ceic.ac.cn/CD20231118174835.html"
},
{
"id": 7,
"name": "参数8_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "震级(M)"
},
{
"id": 8,
"name": "参数9_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "发震时刻(UTC+8)"
},
{
"id": 9,
"name": "参数10_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "纬度(°)"
},
{
"id": 10,
"name": "参数11_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "经度(°)"
},
{
"id": 11,
"name": "参数12_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "深度(千米)"
},
{
"id": 12,
"name": "参数13_文本",
"desc": "",
"type": "text",
"recordASField": 1,
"exampleValue": "参考位置"
}
],
"graph": [
{
"index": 0,
"id": 0,
"parentId": 0,
"type": -1,
"option": 0,
"title": "root",
"sequence": [1, 2, 3, 4],
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0
},
"isInLoop": false
},
{
"id": 1,
"index": 1,
"parentId": 0,
"type": 0,
"option": 1,
"title": "打开网页",
"sequence": [],
"isInLoop": false,
"position": 0,
"parameters": {
"useLoop": false,
"xpath": "",
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "https://www.ceic.ac.cn/history",
"links": "https://www.ceic.ac.cn/history",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
},
{
"id": 2,
"index": 2,
"parentId": 0,
"type": 0,
"option": 4,
"title": "输入文字",
"sequence": [],
"isInLoop": false,
"position": 1,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[@id=\"weidu1\"]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"value": "12",
"index": 0,
"allXPaths": [
"/html/body/div[1]/div[3]/div[1]/div[1]/div[1]/form[1]/div[2]/input[1]",
"//input[contains(., '')]",
"id(\"weidu1\")",
"//INPUT[@class='span1']",
"//INPUT[@name='weidu1']",
"/html/body/div[last()-3]/div[last()-1]/div/div/div[last()-1]/form/div[last()-3]/input[last()-1]"
]
}
},
{
"id": 3,
"index": 3,
"parentId": 0,
"type": 0,
"option": 2,
"title": "点击查询",
"sequence": [],
"isInLoop": false,
"position": 2,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[@id=\"search\"]",
"iframe": false,
"wait": 2,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"clickWay": 0,
"maxWaitTime": 10,
"paras": [],
"alertHandleType": 0,
"allXPaths": [
"/html/body/div[1]/div[3]/div[1]/div[1]/div[1]/form[1]/div[5]/a[1]",
"//a[contains(., '查询')]",
"id(\"search\")",
"//A[@class='check']",
"/html/body/div[last()-3]/div[last()-1]/div/div/div[last()-1]/form/div/a"
]
}
},
{
"id": 4,
"index": 4,
"parentId": 0,
"type": 1,
"option": 8,
"title": "循环点击单个元素",
"sequence": [6, 5],
"isInLoop": false,
"position": 3,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": false,
"xpath": "//a[contains(., '»')]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"loopType": 0,
"pathList": "",
"textList": "",
"code": "",
"waitTime": 0,
"exitCount": 0,
"exitElement": "//body",
"historyWait": 2,
"breakMode": 0,
"breakCode": "",
"breakCodeWaitTime": 0,
"allXPaths": [
"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/div[2]/div[1]/div[1]/ul[1]/li[10]/a[1]",
"//a[contains(., '»')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div/div/div/ul/li[last()-1]/a"
]
}
},
{
"id": 6,
"index": 5,
"parentId": 4,
"type": 0,
"option": 2,
"title": "点击»",
"sequence": [],
"isInLoop": true,
"position": 1,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": true,
"xpath": "",
"iframe": false,
"wait": 2,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"clickWay": 0,
"maxWaitTime": 10,
"paras": [],
"alertHandleType": 0,
"allXPaths": [
"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/div[2]/div[1]/div[1]/ul[1]/li[10]/a[1]",
"//a[contains(., '»')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div/div/div/ul/li[last()-1]/a"
],
"loopType": 0
}
},
{
"id": 5,
"index": 6,
"parentId": 4,
"type": 1,
"option": 8,
"title": "循环采集数据",
"sequence": [7],
"isInLoop": true,
"position": 0,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": false,
"xpath": "/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/div[1]/table[1]/tbody[1]/tr",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"loopType": 1,
"pathList": "",
"textList": "",
"code": "",
"waitTime": 0,
"exitCount": 0,
"exitElement": "//body",
"historyWait": 2,
"breakMode": 0,
"breakCode": "",
"breakCodeWaitTime": 0,
"allXPaths": [
"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/div[1]/table[1]/tbody[1]/tr[1]",
"//tr[contains(., '震级(M)发震时刻(')]",
"//TR[@class='speed-tr-h1']",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]"
]
}
},
{
"id": 7,
"index": 7,
"parentId": 5,
"type": 0,
"option": 3,
"title": "提取数据",
"sequence": [],
"isInLoop": true,
"position": 0,
"parameters": {
"history": 7,
"tabIndex": -1,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"clear": 0,
"newLine": 1,
"paras": [
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数1_文本",
"desc": "",
"relativeXPath": "/td[1]",
"allXPaths": [
"/td[1]",
"//td[contains(., '3.3')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td[last()-5]"
],
"exampleValues": [{ "num": 0, "value": "3.3" }],
"unique_index": "/td[1]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数2_文本",
"desc": "",
"relativeXPath": "/td[2]",
"allXPaths": [
"/td[2]",
"//td[contains(., '2023-11-18')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td[last()-4]"
],
"exampleValues": [{ "num": 0, "value": "2023-11-1817:48:35" }],
"unique_index": "/td[2]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数3_文本",
"desc": "",
"relativeXPath": "/td[3]",
"allXPaths": [
"/td[3]",
"//td[contains(., '36.55')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td[last()-3]"
],
"exampleValues": [{ "num": 0, "value": "36.55" }],
"unique_index": "/td[3]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数4_文本",
"desc": "",
"relativeXPath": "/td[4]",
"allXPaths": [
"/td[4]",
"//td[contains(., '106.31')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td[last()-2]"
],
"exampleValues": [{ "num": 0, "value": "106.31" }],
"unique_index": "/td[4]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数5_文本",
"desc": "",
"relativeXPath": "/td[5]",
"allXPaths": [
"/td[5]",
"//td[contains(., '15')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td[last()-1]"
],
"exampleValues": [{ "num": 0, "value": "15" }],
"unique_index": "/td[5]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 1,
"contentType": 0,
"relative": true,
"name": "参数6_链接文本",
"desc": "",
"relativeXPath": "/td[6]/a[1]",
"allXPaths": [
"/td[6]/a[1]",
"//a[contains(., '宁夏中卫市海原县')]",
"id(\"cid\")",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td/a"
],
"exampleValues": [{ "num": 0, "value": "宁夏中卫市海原县" }],
"unique_index": "/td[6]/a[1]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 2,
"contentType": 0,
"relative": true,
"name": "参数7_链接地址",
"desc": "",
"relativeXPath": "/td[6]/a[1]",
"allXPaths": [
"/td[6]/a[1]",
"//a[contains(., '宁夏中卫市海原县')]",
"id(\"cid\")",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr/td/a"
],
"exampleValues": [
{
"num": 0,
"value": "https://news.ceic.ac.cn/CD20231118174835.html"
}
],
"unique_index": "/td[6]/a[1]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数8_文本",
"desc": "",
"relativeXPath": "/th[1]",
"allXPaths": [
"/th[1]",
"//th[contains(., '震级(M)')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th[last()-5]"
],
"exampleValues": [{ "num": 1, "value": "震级(M)" }],
"unique_index": "/th[1]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数9_文本",
"desc": "",
"relativeXPath": "/th[2]",
"allXPaths": [
"/th[2]",
"//th[contains(., '发震时刻(UTC+8')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th[last()-4]"
],
"exampleValues": [{ "num": 1, "value": "发震时刻(UTC+8)" }],
"unique_index": "/th[2]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数10_文本",
"desc": "",
"relativeXPath": "/th[3]",
"allXPaths": [
"/th[3]",
"//th[contains(., '纬度(°)')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th[last()-3]"
],
"exampleValues": [{ "num": 1, "value": "纬度(°)" }],
"unique_index": "/th[3]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数11_文本",
"desc": "",
"relativeXPath": "/th[4]",
"allXPaths": [
"/th[4]",
"//th[contains(., '经度(°)')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th[last()-2]"
],
"exampleValues": [{ "num": 1, "value": "经度(°)" }],
"unique_index": "/th[4]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数12_文本",
"desc": "",
"relativeXPath": "/th[5]",
"allXPaths": [
"/th[5]",
"//th[contains(., '深度(千米)')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th[last()-1]"
],
"exampleValues": [{ "num": 1, "value": "深度(千米)" }],
"unique_index": "/th[5]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
},
{
"nodeType": 0,
"contentType": 1,
"relative": true,
"name": "参数13_文本",
"desc": "",
"relativeXPath": "/th[6]",
"allXPaths": [
"/th[6]",
"//th[contains(., '参考位置')]",
"/html/body/div[last()-3]/div[last()-1]/div/div/div/div/div[last()-1]/table/tbody/tr[last()-20]/th"
],
"exampleValues": [{ "num": 1, "value": "参考位置" }],
"unique_index": "/th[6]",
"iframe": false,
"default": "",
"paraType": "text",
"recordASField": 1,
"beforeJS": "",
"beforeJSWaitTime": 0,
"JS": "",
"JSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"downloadPic": 0
}
],
"loopType": 1
}
}
]
}

223
ElectronJS/tasks/249.json Normal file
View File

@ -0,0 +1,223 @@
{
"id": 249,
"name": "京东全球版-专业的综合网上购物商城",
"url": "https://www.jd.com",
"links": "https://google.com",
"create_time": "",
"update_time": "12/10/2023, 2:19:08 PM",
"version": "0.6.0",
"saveThreshold": 10,
"quitWaitTime": 60,
"environment": 0,
"maximizeWindow": 0,
"maxViewLength": 15,
"recordLog": 1,
"outputFormat": "xlsx",
"saveName": "current_time",
"inputExcel": "",
"startFromExit": 0,
"pauseKey": "p",
"containJudge": false,
"desc": "https://www.jd.com",
"inputParameters": [
{
"id": 0,
"name": "urlList_0",
"nodeId": 1,
"nodeName": "打开网页1",
"value": "https://www.jd.com",
"desc": "要采集的网址列表,多行以\\n分开",
"type": "text",
"exampleValue": "https://www.jd.com"
},
{
"id": 1,
"name": "loopText_1",
"nodeId": 3,
"nodeName": "循环",
"desc": "要输入的文本/网址,多行以\\n分开",
"type": "text",
"exampleValue": "https://baidu.com\nhttps://baidu1.com",
"value": "https://baidu.com\nhttps://baidu1.com"
},
{
"id": 2,
"name": "urlList_2",
"nodeId": 4,
"nodeName": "打开网页2",
"value": "https://google.com",
"desc": "要采集的网址列表,多行以\\n分开",
"type": "text",
"exampleValue": "https://google.com"
}
],
"outputParameters": [],
"graph": [
{
"index": 0,
"id": 0,
"parentId": 0,
"type": -1,
"option": 0,
"title": "root",
"sequence": [1, 4, 3],
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0
},
"isInLoop": false
},
{
"id": 1,
"index": 1,
"parentId": 0,
"type": 0,
"option": 1,
"title": "打开网页1",
"sequence": [],
"isInLoop": false,
"position": 0,
"parameters": {
"useLoop": false,
"xpath": "",
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "https://www.jd.com",
"links": "https://www.jd.com",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
},
{
"id": 4,
"index": 2,
"parentId": 3,
"type": 0,
"option": 1,
"title": "打开网页3",
"sequence": [],
"isInLoop": true,
"position": 0,
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": true,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "about:blank",
"links": "about:blank",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
},
{
"id": 3,
"index": 3,
"parentId": 0,
"type": 1,
"option": 8,
"title": "循环",
"sequence": [2],
"isInLoop": false,
"position": 2,
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"loopType": 4,
"pathList": "",
"textList": "https://baidu.com\nhttps://baidu1.com",
"code": "",
"waitTime": 0,
"exitCount": 0,
"exitElement": "//body",
"historyWait": 2,
"breakMode": 0,
"breakCode": "",
"breakCodeWaitTime": 0
}
},
{
"id": 2,
"index": 4,
"parentId": 0,
"type": 0,
"option": 1,
"title": "打开网页2",
"sequence": [],
"isInLoop": false,
"position": 1,
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "about:blank",
"links": "https://google.com",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
}
]
}

147
ElectronJS/tasks/250.json Normal file
View File

@ -0,0 +1,147 @@
{
"id": 250,
"name": "京东全球版-专业的综合网上购物商城",
"url": "https://www.jd.com",
"links": "https://www.jd.com",
"create_time": "",
"update_time": "12/10/2023, 2:24:56 PM",
"version": "0.6.0",
"saveThreshold": 10,
"quitWaitTime": 60,
"environment": 0,
"maximizeWindow": 0,
"maxViewLength": 15,
"recordLog": 1,
"outputFormat": "xlsx",
"saveName": "current_time",
"inputExcel": "",
"startFromExit": 0,
"pauseKey": "p",
"containJudge": false,
"desc": "https://www.jd.com",
"inputParameters": [
{
"id": 0,
"name": "urlList_0",
"nodeId": 1,
"nodeName": "打开网页",
"value": "https://www.jd.com",
"desc": "要采集的网址列表,多行以\\n分开",
"type": "text",
"exampleValue": "https://www.jd.com"
}
],
"outputParameters": [
{
"id": 0,
"name": "执行JavaScript1",
"desc": "自定义操作返回的数据",
"type": "text",
"recordASField": 0,
"exampleValue": ""
}
],
"graph": [
{
"index": 0,
"id": 0,
"parentId": 0,
"type": -1,
"option": 0,
"title": "root",
"sequence": [1, 2],
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0
},
"isInLoop": false
},
{
"id": 1,
"index": 1,
"parentId": 0,
"type": 0,
"option": 1,
"title": "打开网页",
"sequence": [],
"isInLoop": false,
"position": 0,
"parameters": {
"useLoop": false,
"xpath": "",
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "https://www.jd.com",
"links": "https://www.jd.com",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
},
{
"id": 2,
"index": 2,
"parentId": 0,
"type": 0,
"option": 5,
"title": "执行JavaScript1",
"sequence": [],
"isInLoop": false,
"position": 1,
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"clear": 0,
"newLine": 1,
"codeMode": 0,
"code": "document.body.style.color = \"blue\"",
"waitTime": 0,
"recordASField": 0,
"paraType": "text",
"emailConfig": {
"host": "",
"port": 465,
"username": "",
"password": "",
"from": "",
"to": "",
"subject": "",
"content": ""
}
}
}
]
}

274
ElectronJS/tasks/251.json Normal file
View File

@ -0,0 +1,274 @@
{
"id": 251,
"name": "Select · Bootstrap v5.3",
"url": "https://getbootstrap.com/docs/5.3/forms/select/",
"links": "https://getbootstrap.com/docs/5.3/forms/select/",
"create_time": "12/10/2023, 2:29:23 PM",
"update_time": "12/10/2023, 2:29:23 PM",
"version": "0.6.0",
"saveThreshold": 10,
"quitWaitTime": 60,
"environment": 0,
"maximizeWindow": 0,
"maxViewLength": 15,
"recordLog": 1,
"outputFormat": "xlsx",
"saveName": "current_time",
"inputExcel": "",
"startFromExit": 0,
"pauseKey": "p",
"containJudge": false,
"desc": "https://getbootstrap.com/docs/5.3/forms/select/",
"inputParameters": [
{
"id": 0,
"name": "urlList_0",
"nodeId": 1,
"nodeName": "打开网页",
"value": "https://getbootstrap.com/docs/5.3/forms/select/",
"desc": "要采集的网址列表,多行以\\n分开",
"type": "text",
"exampleValue": "https://getbootstrap.com/docs/5.3/forms/select/"
}
],
"outputParameters": [],
"graph": [
{
"index": 0,
"id": 0,
"parentId": 0,
"type": -1,
"option": 0,
"title": "root",
"sequence": [1, 2, 3, 5, 6],
"parameters": {
"history": 1,
"tabIndex": 0,
"useLoop": false,
"xpath": "",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0
},
"isInLoop": false
},
{
"id": 1,
"index": 1,
"parentId": 0,
"type": 0,
"option": 1,
"title": "打开网页",
"sequence": [],
"isInLoop": false,
"position": 0,
"parameters": {
"useLoop": false,
"xpath": "",
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"url": "https://getbootstrap.com/docs/5.3/forms/select/",
"links": "https://getbootstrap.com/docs/5.3/forms/select/",
"maxWaitTime": 10,
"scrollType": 0,
"scrollCount": 1,
"scrollWaitTime": 1,
"cookies": ""
}
},
{
"id": 2,
"index": 2,
"parentId": 0,
"type": 0,
"option": 6,
"title": "切换下拉选项",
"sequence": [],
"isInLoop": false,
"position": 1,
"parameters": {
"history": 4,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[contains(@class, \"bd-content\")]/div[1]/div[1]/select[1]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"optionMode": 0,
"optionValue": "One",
"index": 0,
"allXPaths": [
"/html/body/div[2]/main[1]/div[3]/div[1]/div[1]/select[1]",
"//select[contains(., 'Open th')]",
"//SELECT[@class='form-select']",
"/html/body/div[last()-4]/main/div/div[last()-5]/div[last()-2]/select"
]
}
},
{
"id": 3,
"index": 3,
"parentId": 0,
"type": 0,
"option": 6,
"title": "切换下拉选项",
"sequence": [],
"isInLoop": false,
"position": 2,
"parameters": {
"history": 4,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[contains(@class, \"bd-content\")]/div[1]/div[1]/select[1]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"optionMode": "1",
"optionValue": "2",
"index": 0,
"allXPaths": [
"/html/body/div[2]/main[1]/div[3]/div[1]/div[1]/select[1]",
"//select[contains(., 'Open th')]",
"//SELECT[@class='form-select']",
"/html/body/div[last()-4]/main/div/div[last()-5]/div[last()-2]/select"
]
}
},
{
"id": -1,
"index": 4,
"parentId": 0,
"type": 0,
"option": 6,
"title": "切换下拉选项",
"sequence": [],
"isInLoop": false,
"position": 3,
"parameters": {
"history": 4,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[contains(@class, \"bd-content\")]/div[1]/div[1]/select[1]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"optionMode": "2",
"optionValue": "1",
"index": 0,
"allXPaths": [
"/html/body/div[2]/main[1]/div[3]/div[1]/div[1]/select[1]",
"//select[contains(., 'Open th')]",
"//SELECT[@class='form-select']",
"/html/body/div[last()-4]/main/div/div[last()-5]/div[last()-2]/select"
]
}
},
{
"id": 4,
"index": 5,
"parentId": 0,
"type": 0,
"option": 6,
"title": "切换下拉选项",
"sequence": [],
"isInLoop": false,
"position": 3,
"parameters": {
"history": 4,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[contains(@class, \"bd-content\")]/div[1]/div[1]/select[1]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"optionMode": "2",
"optionValue": "1",
"index": 0,
"allXPaths": [
"/html/body/div[2]/main[1]/div[3]/div[1]/div[1]/select[1]",
"//select[contains(., 'Open th')]",
"//SELECT[@class='form-select']",
"/html/body/div[last()-4]/main/div/div[last()-5]/div[last()-2]/select"
]
}
},
{
"id": 5,
"index": 6,
"parentId": 0,
"type": 0,
"option": 6,
"title": "切换下拉选项",
"sequence": [],
"isInLoop": false,
"position": 4,
"parameters": {
"history": 4,
"tabIndex": -1,
"useLoop": false,
"xpath": "//*[contains(@class, \"bd-content\")]/div[1]/div[1]/select[1]",
"iframe": false,
"wait": 0,
"waitType": 0,
"beforeJS": "",
"beforeJSWaitTime": 0,
"afterJS": "",
"afterJSWaitTime": 0,
"waitElement": "",
"waitElementTime": 10,
"waitElementIframeIndex": 0,
"optionMode": "3",
"optionValue": "Three",
"index": 0,
"allXPaths": [
"/html/body/div[2]/main[1]/div[3]/div[1]/div[1]/select[1]",
"//select[contains(., 'Open th')]",
"//SELECT[@class='form-select']",
"/html/body/div[last()-4]/main/div/div[last()-5]/div[last()-2]/select"
]
}
}
]
}

View File

@ -12,7 +12,7 @@
"justMyCode": false,
// "args": ["--ids", "[7]", "--read_type", "remote", "--headless", "0"]
// "args": ["--ids", "[9]", "--read_type", "remote", "--headless", "0", "--saved_file_name", "YOUTUBE"]
"args": ["--ids", "[95]", "--headless", "0", "--user_data", "0", "--keyboard", "0"]
"args": ["--ids", "[10]", "--headless", "0", "--user_data", "0", "--keyboard", "0"]
// "args": "--ids '[97]' --user_data 1 --server_address http://localhost:8074 --config_folder '/Users/naibo/Documents/EasySpider/ElectronJS/' --headless 0 --read_type remote --config_file_name config.json --saved_file_name"
}
]

View File

@ -1507,13 +1507,25 @@ class BrowserThread(Thread):
click_way = 0
try:
if click_way == 0: # 用selenium的点击方法
actions = ActionChains(self.browser) # 实例化一个action对象
actions.click(element).perform()
try:
actions = ActionChains(self.browser) # 实例化一个action对象
actions.click(element).perform()
except Exception as e:
self.browser.execute_script("arguments[0].scrollIntoView();", element)
try:
actions = ActionChains(self.browser) # 实例化一个action对象
actions.click(element).perform()
except Exception as e:
self.print_and_log(f"Selenium点击元素{path}失败将尝试使用JavaScript点击")
self.print_and_log(f"Failed to click element {path} with Selenium, will try to click with JavaScript")
script = 'var result = document.evaluate(`' + path + \
'`, document, null, XPathResult.ANY_TYPE, null);for(let i=0;i<arguments[0];i++){result.iterateNext();} result.iterateNext().click();'
self.browser.execute_script(script, str(index)) # 用js的点击方法
elif click_way == 1: # 用js的点击方法
script = 'var result = document.evaluate(`' + path + \
'`, document, null, XPathResult.ANY_TYPE, null);for(let i=0;i<arguments[0];i++){result.iterateNext();} result.iterateNext().click();'
self.browser.execute_script(script, str(index)) # 用js的点击方法
# self.recordLog("点击元素|Click element: " + path)
self.recordLog("点击元素|Click element: " + path)
except TimeoutException:
self.print_and_log(
'Time out after set seconds when loading clicked page')

View File

@ -1 +1 @@
{"language":"en"}
{"language":"zh"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -63,6 +63,23 @@ document.addEventListener("mousemove", function() {
if (x >= divx1 && x <= divx2 && y >= divy1 && y <= divy2) {
tooltips = true;
return;
}
//如果鼠标在ID为notification_of_easyspider内则点击和选中失效
try {
let notification_of_easyspider = document.getElementsByClassName("notification_of_easyspider")[0];
let x = event.clientX;
let y = event.clientY;
let divx1 = notification_of_easyspider.offsetLeft;
let divy1 = notification_of_easyspider.offsetTop;
let divx2 = notification_of_easyspider.offsetLeft + notification_of_easyspider.offsetWidth;
let divy2 = notification_of_easyspider.offsetTop + notification_of_easyspider.offsetHeight;
if (y >= divy1 - 100 && y <= divy2 + 100) {
tooltips = true;
// console.log("notification_of_easyspider");
return;
}
} catch (e) {
}
global.oe = document.elementFromPoint(event.x, event.y);
if (global.oe == global.tdiv) {

View File

@ -1,22 +1,9 @@
//实现与后台和流程图部分的交互
import {getElementXPaths, global, readXPath, isInIframe} from "./global.js";
// var startMsg = { "type": 0, msg: ""};
//
// chrome.runtime.sendMessage(startMsg, function(response) {
// console.log(response.msg);
// }); //每次打开新页面的时候需要告诉后台
// chrome.runtime.onMessage.addListener(
// function(request, sender, sendResponse) {
// if (request["type"] == 1){
// sendResponse("回答处理结果");
// }
// }
// );
import {getElementXPaths, global, readXPath, isInIframe, clearEl} from "./global.js";
global.ws = new WebSocket("ws://localhost:8084");
global.ws.onopen = function() {
global.ws.onopen = function () {
// Web Socket 已连接上,使用 send() 方法发送数据
console.log("已连接");
let message = {
@ -28,13 +15,26 @@ global.ws.onopen = function() {
};
this.send(JSON.stringify(message));
};
global.ws.onmessage = function(evt) {
global.ws.onmessage = function (evt) {
evt = JSON.parse(evt.data);
if (evt["type"] == "0") { //0代表更新参数添加索引值
chrome.storage.local.set({ "parameterNum": parseInt(evt["value"]) }); //修改值
if (evt["type"] == "update_parameter_num") { //0代表更新参数添加索引值
chrome.storage.local.set({"parameterNum": parseInt(evt["value"])}); //修改值
console.log("更新参数添加索引值为:" + evt["value"]);
} else if (evt["type"] == "notify") { //1代表更新参数
createNotification(LANG(evt["msg_zh"], evt["msg_en"]), evt["level"]);
} else if (evt["type"] == "cancelSelection") { //试运行点击元素后取消选中元素
clearEl();
}
};
function LANG(zh, en) {
if (global.lang == "zh") {
return zh;
} else {
return en;
}
}
export function input(value) {
let message = {
"type": "inputText",
@ -55,7 +55,7 @@ export function input(value) {
// msg = { type: 2, value: value, xpath: message.xpath, id: global.id};
let message_keyboard = {
type: 2, //消息类型2代表键盘输入
message: { "keyboardStr": value, "xpath": message.xpath, "iframe": global.iframe, "id": global.id } // {}全选{BS}退格
message: {"keyboardStr": value, "xpath": message.xpath, "iframe": global.iframe, "id": global.id} // {}全选{BS}退格
};
global.ws.send(JSON.stringify(message_keyboard));
}
@ -81,7 +81,7 @@ export function sendSingleClick() {
global.ws.send(JSON.stringify(message_action));
}
export function sendChangeOption(optionMode, optionValue){
export function sendChangeOption(optionMode, optionValue) {
let message = {
"type": "changeOption",
"optionMode": optionMode,
@ -101,7 +101,7 @@ export function sendChangeOption(optionMode, optionValue){
global.ws.send(JSON.stringify(message_action));
}
export function sendMouseMove(){
export function sendMouseMove() {
let message = {
"type": "mouseMove",
"history": history.length, //记录history的长度
@ -120,7 +120,7 @@ export function sendMouseMove(){
global.ws.send(JSON.stringify(message_action));
}
export function sendLoopMouseMove(){
export function sendLoopMouseMove() {
let message = {
"type": "loopMouseMove",
"history": history.length, //记录history的长度
@ -168,8 +168,75 @@ export function collectSingle() {
message: {"pipe": JSON.stringify(message)}
};
global.ws.send(JSON.stringify(message_action));
createNotification(LANG("采集成功", "Collect successfully"), "success");
}
function createNotification(text, type="info") {
// 创建通知元素
let notification = document.createElement('div');
notification.className = 'notification_of_easyspider'; // 使用 class 方便后续添加样式
notification.setAttribute("data-timestamp", new Date().getTime()); // 用于清除通知
// 设置通知文本
notification.innerText = text;
// 定义与添加样式
let cssText = `
position: fixed;
bottom: 20px; /* 距底部20px */
right: -320px; /* 初始位置在屏幕右侧假设通知框宽度320px */
min-width: 300px;
padding: 10px 20px;
color: white;
z-index: 2147483641;
border-radius: 4px;
text-align: center;
font-size: 15px;
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
transition: right 0.5s ease-in-out; /* 动画效果 */
`;
notification.style.cssText = cssText;
if (type === "success") {
notification.style.backgroundColor = 'rgb(103, 194, 58)';
} else if (type === "info") {
notification.style.backgroundColor = '#00a8ff';
} else if (type === "warning") {
notification.style.backgroundColor = 'rgb(230, 162, 60)';
} else if (type === "error") {
notification.style.backgroundColor = '#ff6b6b';
}
// 将通知添加到页面中
document.body.appendChild(notification);
// 触发动画,通知从右向左滑入
setTimeout(function () {
notification.style.right = '20px'; // 调整距离左边的位置
}, 100);
let timeoutInterval = 1500 * text.length / 5;
// 设置退出动画,通知从右向左滑出
setTimeout(function () {
notification.style.right = '-320px'; // 向左退出
// 确定动画结束后移除通知
notification.addEventListener('transitionend', function () {
if (notification.parentNode === document.body) {
document.body.removeChild(notification); // 避免移除已经不存在的元素
}
});
}, timeoutInterval + 500); // 通知停留时间加上动画时间
}
setInterval(function () {
let notifications = document.getElementsByClassName("notification_of_easyspider");
for (let i = 0; i < notifications.length; i++) {
if (new Date().getTime() - parseInt(notifications[i].getAttribute("data-timestamp")) > 10000) {
if (notifications[i].parentNode === document.body) {
document.body.removeChild(notifications[i]); // 避免移除已经不存在的元素
}
}
}
}, 3000);
//采集无规律多元素
export function collectMultiNoPattern() {
let message = {
@ -201,7 +268,7 @@ export function collectMultiWithPattern() {
"isDescendents": global.app._data.selectedDescendents, //标记是否采集的是子元素
"parameters": global.outputParameters,
};
for(let i=0;i<global.outputParameters.length;i++){
for (let i = 0; i < global.outputParameters.length; i++) {
global.outputParameters[i]["exampleValues"] = [global.outputParameters[i]["exampleValues"][0]];
}
if (!detectAllSelected()) //如果不是全部选中的话

View File

@ -52,6 +52,7 @@
"identity",
"storage",
"tabs",
"scripting"
"scripting",
"notifications"
]
}

View File

@ -3,7 +3,7 @@
min-height: 300px;
background-color: white;
position: fixed;
z-index: 2147483647;
z-index: 2147483640;
right: 30px;
bottom: 30px;
font-size: 13px !important;