mirror of
https://github.com/NaiboWang/EasySpider.git
synced 2025-04-16 16:26:56 +08:00
Ctrl+Click & Hint of mobile mode & Default Browser Location & Click with coordinate
This commit is contained in:
parent
ea2d679dd4
commit
7901ee2877
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
{"webserver_address":"http://localhost","webserver_port":8074,"user_data_folder":"./user_data","debug":false,"copyright":1,"sys_version":"x64","mysql_config_path":"./mysql_config.json","absolute_user_data_folder":"/Users/naibo/Documents/EasySpider/ElectronJS/user_data"}
|
||||
{"webserver_address":"http://localhost","webserver_port":8074,"user_data_folder":"","debug":false,"copyright":1,"sys_version":"x64","mysql_config_path":"./mysql_config.json","absolute_user_data_folder":"/Users/naibo/Documents/EasySpider/ElectronJS/user_data"}
|
@ -108,8 +108,8 @@ let invoke_window = null;
|
||||
function createWindow() {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 550,
|
||||
height: 750,
|
||||
width: 600,
|
||||
height: 800,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'src/js/preload.js')
|
||||
},
|
||||
@ -231,7 +231,7 @@ async function findElementAcrossAllWindows(msg, notifyBrowser = true, scrollInto
|
||||
xpath = msg.message.xpath;
|
||||
} catch {
|
||||
//如果msg.pathList存在,说明是循环中的元素
|
||||
if(msg.pathList != undefined && msg.pathList != null && msg.pathList != ""){
|
||||
if (msg.pathList != undefined && msg.pathList != null && msg.pathList != "") {
|
||||
xpath = msg.pathList[0].trim();
|
||||
} else {
|
||||
xpath = msg.xpath;
|
||||
@ -301,15 +301,18 @@ async function beginInvoke(msg, ws) {
|
||||
// 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") {
|
||||
const {windowManager} = require("node-window-manager");
|
||||
const window = windowManager.getActiveWindow();
|
||||
console.log(window);
|
||||
windowManager.requestAccessibility();
|
||||
// Sets the active window's bounds.
|
||||
let size = screen.getPrimaryDisplay().workAreaSize
|
||||
let width = parseInt(size.width)
|
||||
let height = parseInt(size.height * 0.6)
|
||||
window.setBounds({x: 0, y: size.height * 0.4, height: height, width: width});
|
||||
// 非用户信息模式下,设置窗口位置
|
||||
if (config.user_data_folder == null || config.user_data_folder == undefined || config.user_data_folder == "") {
|
||||
const {windowManager} = require("node-window-manager");
|
||||
const window = windowManager.getActiveWindow();
|
||||
console.log(window);
|
||||
windowManager.requestAccessibility();
|
||||
// Sets the active window's bounds.
|
||||
let size = screen.getPrimaryDisplay().workAreaSize
|
||||
let width = parseInt(size.width)
|
||||
let height = parseInt(size.height * 0.6)
|
||||
window.setBounds({x: 0, y: size.height * 0.4, height: height, width: width});
|
||||
}
|
||||
}
|
||||
flowchart_window.show();
|
||||
// flowchart_window.openDevTools();
|
||||
@ -337,7 +340,7 @@ async function beginInvoke(msg, ws) {
|
||||
if (type.indexOf("Click") >= 0 || type.indexOf("Move") >= 0) {
|
||||
let element = await findElementAcrossAllWindows(message, notifyBrowser = true, scrollIntoView = false);
|
||||
if (type.indexOf("Click") >= 0) {
|
||||
await click_element(element);
|
||||
await click_element(element, type);
|
||||
} else if (type.indexOf("Move") >= 0) {
|
||||
await driver.actions().move({origin: element}).perform();
|
||||
}
|
||||
@ -366,6 +369,9 @@ async function beginInvoke(msg, ws) {
|
||||
}
|
||||
xpath = parent_xpath + xpath;
|
||||
}
|
||||
if (xpath.includes("point(")) {
|
||||
xpath = "//body";
|
||||
}
|
||||
let elementInfo = {"iframe": parameters.iframe, "xpath": xpath, "id": -1};
|
||||
//用于跳转到元素位置
|
||||
let element = await findElementAcrossAllWindows(elementInfo);
|
||||
@ -492,8 +498,13 @@ async function beginInvoke(msg, ws) {
|
||||
}
|
||||
}
|
||||
} else if (option == 2 || option == 7) { //点击事件
|
||||
let elementInfo = {"iframe": parameters.iframe, "xpath": parameters.xpath, "id": -1};
|
||||
if (parameters.useLoop) {
|
||||
let xpath = parameters.xpath;
|
||||
let point = parameters.xpath;
|
||||
if (xpath.includes("point(")) {
|
||||
xpath = "//body"
|
||||
}
|
||||
let elementInfo = {"iframe": parameters.iframe, "xpath": xpath, "id": -1};
|
||||
if (parameters.useLoop && !parameters.xpath.includes("point(")) {
|
||||
let parent_node = JSON.parse(msg.message.parentNode);
|
||||
let parent_xpath = parent_node.parameters.xpath;
|
||||
if (parent_node.parameters.loopType == 2) {
|
||||
@ -504,7 +515,11 @@ async function beginInvoke(msg, ws) {
|
||||
let element = await findElementAcrossAllWindows(elementInfo, notifyBrowser = false); //通过此函数找到元素并切换到对应的窗口
|
||||
await execute_js(parameters.beforeJS, element, parameters.beforeJSWaitTime);
|
||||
if (option == 2) {
|
||||
await click_element(element);
|
||||
if (parameters.xpath.includes("point(")) {
|
||||
await click_element(element, point);
|
||||
} else {
|
||||
await click_element(element);
|
||||
}
|
||||
let alertHandleType = parameters.alertHandleType;
|
||||
if (alertHandleType == 1) {
|
||||
try {
|
||||
@ -731,11 +746,25 @@ async function beginInvoke(msg, ws) {
|
||||
}
|
||||
}
|
||||
|
||||
async function click_element(element) {
|
||||
async function click_element(element, type = "click") {
|
||||
try {
|
||||
await element.click();
|
||||
//ctrl+click
|
||||
// await driver.actions().keyDown(Key.CONTROL).click(element).keyUp(Key.CONTROL).perform();
|
||||
if (type == "loopClickEvery") {
|
||||
await driver.actions().keyDown(Key.CONTROL).click(element).keyUp(Key.CONTROL).perform();
|
||||
} else if (type.includes("point(")) {
|
||||
//point(10, 20)表示点击坐标为(10, 20)的位置
|
||||
let point = type.substring(6, type.length - 1).split(",");
|
||||
let x = parseInt(point[0]);
|
||||
let y = parseInt(point[1]);
|
||||
// let actions = driver.actions();
|
||||
// await actions.move({origin: element}).perform();
|
||||
// await actions.move({x: x, y: y}).perform();
|
||||
// await actions.click().perform();
|
||||
let script = `document.elementFromPoint(${x}, ${y}).click();`;
|
||||
await driver.executeScript(script);
|
||||
} else {
|
||||
await element.click();
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
await driver.executeScript("arguments[0].click();", element);
|
||||
@ -819,12 +848,12 @@ wss.on('connection', function (ws) {
|
||||
await driver.switchTo().window(current_handle);
|
||||
console.log("New tab opened, change current_handle to: ", current_handle);
|
||||
// 调整浏览器窗口大小,不然扩展会白屏
|
||||
// let size = await driver.manage().window().getRect();
|
||||
// let width = size.width;
|
||||
// let height = size.height;
|
||||
// await driver.manage().window().setRect({width: width, height: height + 10});
|
||||
// // height = height - 1;
|
||||
// await driver.manage().window().setRect({width: width, height: height});
|
||||
let size = await driver.manage().window().getRect();
|
||||
let width = size.width;
|
||||
let height = size.height;
|
||||
await driver.manage().window().setRect({width: width, height: height + 10});
|
||||
// height = height - 1;
|
||||
await driver.manage().window().setRect({width: width, height: height});
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
handle_pairs[msg.message.id] = current_handle;
|
||||
@ -894,6 +923,8 @@ async function runBrowser(lang = "en", user_data_folder = '', mobile = false) {
|
||||
options.addArguments("--user-data-dir=" + dir);
|
||||
config.user_data_folder = user_data_folder;
|
||||
fs.writeFileSync(path.join(task_server.getDir(), "config.json"), JSON.stringify(config));
|
||||
} else {
|
||||
config.user_data_folder = "";
|
||||
}
|
||||
if (mobile) {
|
||||
const mobileEmulation = {
|
||||
|
BIN
ElectronJS/src/img/toggle.png
Normal file
BIN
ElectronJS/src/img/toggle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -94,9 +94,9 @@ For individual users, EasySpider is a completely free and ad-free open-source so
|
||||
</div>
|
||||
<div v-else-if="step == 1">
|
||||
<h4 style="margin-top: 20px">Please select design mode</h4>
|
||||
<p style="margin-top: 20px; text-align: justify; width:310px; margin-left: 18%">
|
||||
Clean Mode: Start with a clean browser with no cookie/user data.</p>
|
||||
<p style="text-align: justify; width:310px; margin-left: 18%">
|
||||
<p style="margin-top: 20px; text-align: justify; width:290px; margin-left: 25%">
|
||||
Clean Mode: Start with a clean browser with no cookies/user data.</p>
|
||||
<p style="text-align: justify; width:290px; margin-left: 25%">
|
||||
Data Mode: Start with a browser that stores user data such as website login information and cookies.</p>
|
||||
<p><a @click="startDesign('en')"
|
||||
class="btn btn-primary btn-lg"
|
||||
@ -177,10 +177,10 @@ For individual users, EasySpider is a completely free and ad-free open-source so
|
||||
</div>
|
||||
<div v-else-if="step == 1">
|
||||
<h4 style="margin-top: 20px">请选择设计模式</h4>
|
||||
<p style="margin-top: 20px; text-align: left; width:320px; margin-left: 18%">
|
||||
<p style="margin-top: 20px; text-align: left; width:310px; margin-left: 24%">
|
||||
纯净版浏览器:无任何用户信息的浏览器。</p>
|
||||
<p style="text-align: left; width:320px; margin-left: 18%">
|
||||
带用户信息的浏览器:保存有用户数据,如网站的登录信息,cookie的浏览器。</p>
|
||||
<p style="text-align: left; width:310px; margin-left: 24%">
|
||||
带用户信息的浏览器:保存有用户数据,如网站的登录信息,cookies的浏览器。</p>
|
||||
<p><a @click="startDesign('zh')"
|
||||
class="btn btn-primary btn-lg"
|
||||
style="margin-top: 15px; width: 320px;height:60px;padding-top:12px;color:white;">使用纯净版浏览器设计</a>
|
||||
@ -203,7 +203,7 @@ For individual users, EasySpider is a completely free and ad-free open-source so
|
||||
<h4 style="margin-top: 20px">指定用户信息目录</h4>
|
||||
<div style="margin: 0 auto; width:90%">
|
||||
<p style="margin-top: 20px; text-align: left">
|
||||
请在下方指定用户信息目录。设置后,浏览器将加载目录里的cookie,如用户的登录信息等内容,目录不变的情况下,每次设计和执行时浏览器都会加载此目录里的数据。</p>
|
||||
请在下方指定用户信息目录。设置后,浏览器将加载目录里的cookies,如用户的登录信息等内容,目录不变的情况下,每次设计和执行时浏览器都会加载此目录里的数据。</p>
|
||||
<p style="margin-top: 10px; text-align: left">例如:设置了./user_data文件夹,并在设计过程中登录了知乎网站,则下次再次设计或者执行任务时指定./user_data文件夹,打开知乎网站页面会仍然保留之前的登录状态。</p>
|
||||
<p style="margin-top: 10px; text-align: left">如果有多套配置,可以设置不同的目录,每个目录为一套,如果目录不存在将会被自动创建。</p>
|
||||
<p><textarea class="form-control" style="min-height: 50px;"
|
||||
|
@ -146,7 +146,7 @@
|
||||
<p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>Use element located by xpath relative to the loop</p>
|
||||
</div>
|
||||
<div>
|
||||
<label>XPath: <span style="font-size: 30px!important;" title="Relative XPATH writing: start with /, e.g. the loop item XPATH is /html/body/div[1], your input is /*[@id='tab-customer'], then the final addressed xpath is: /html/body/div[1]/*[@id='tab-customer']">☺</span></label>
|
||||
<label>XPath (Or use "point(10,10)" to represent clicking on the web page at coordinate position (10, 10), suitable for the situation when need to click on a blank area to leave popup dialog): <span style="font-size: 30px!important;" title="Relative XPATH writing: start with /, e.g. the loop item XPATH is /html/body/div[1], your input is /*[@id='tab-customer'], then the final addressed xpath is: /html/body/div[1]/*[@id='tab-customer']">☺</span></label>
|
||||
<textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
|
||||
<p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode['parameters']['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">Click here to view other equivalent XPath expressions</button></p>
|
||||
</div>
|
||||
@ -690,11 +690,11 @@ If the expression returns a value greater than 0 or evaluates to True, the opera
|
||||
<input spellcheck=false onkeydown="inputDelete(event)" id="serviceDescription" name="serviceDescription" class="form-control"></input>
|
||||
<label>Export Data Format (Excel/CSV/TXT/Database):</label>
|
||||
<select id="outputFormat" class="form-control">
|
||||
<option value = "xlsx">XLSX (EXCEL, we suggest using the CSV format if the length of a single cell exceeds 500)</option>
|
||||
<option value = "csv">CSV</option>
|
||||
<option value = "txt">TXT</option>
|
||||
<option value = "json">JSON</option>
|
||||
<option value = "mysql">MySQL Database</option>
|
||||
<option value="xlsx">XLSX (Excel file, recommended use CSV format when single cell exceeds 500 characters)</option>
|
||||
<option value="csv">CSV (Recommended for collecting long articles)</option>
|
||||
<option value="txt">TXT</option>
|
||||
<option value="json">JSON</option>
|
||||
<option value="mysql">MySQL Database (recommended for large amounts of data)</option>
|
||||
</select>
|
||||
<label>Export File Name/Database Table Name (Can use ../ to represent relative path to change the file save location,the keyword "current_time" will be replaced with the timestamp when the task is executed):</label>
|
||||
<input spellcheck=false onkeydown="inputDelete(event)" value="current_time" id="saveName" class="form-control"></input>
|
||||
|
@ -146,7 +146,7 @@
|
||||
<p><input spellcheck=false onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用相对循环内的XPath定位到的元素</p>
|
||||
</div>
|
||||
<div>
|
||||
<label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
|
||||
<label>XPath(或者用point(10,10)表示点击网页坐标位置(10, 10)以用来点击空白区域推出弹窗对话框等): <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
|
||||
<textarea spellcheck=false onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
|
||||
<p><button type="button" data-toggle="modal" data-target="#myModal_XPath" @click="changeXPaths(nowNode['parameters']['allXPaths'])" class="btn btn-primary" style="margin-top: 10px">点此查看其他等价的XPath</button></p>
|
||||
</div>
|
||||
@ -691,10 +691,10 @@ print(emotlib.emoji()) # 使用其中的函数。
|
||||
<label>导出数据格式(Excel/CSV/TXT/数据库,<a href="https://www.bilibili.com/video/BV1os4y1679S/" target="_blank">查看MySQL操作教程</a>):</label>
|
||||
<select id="outputFormat" class="form-control">
|
||||
<option value = "xlsx">XLSX(即EXCEL文件,建议单个单元格长度超过500时使用CSV格式存储)</option>
|
||||
<option value = "csv">CSV</option>
|
||||
<option value = "csv">CSV(采集长文章推荐使用此格式)</option>
|
||||
<option value = "txt">TXT</option>
|
||||
<option value = "json">JSON</option>
|
||||
<option value = "mysql">MySQL数据库</option>
|
||||
<option value = "mysql">MySQL数据库(大量数据推荐使用)</option>
|
||||
</select>
|
||||
<label>导出文件名/数据库表格名称(可使用../表示相对路径以改变文件保存位置,名称中的“current_time”会被替换为执行任务时的时间戳):</label>
|
||||
<input spellcheck=false onkeydown="inputDelete(event)" value="current_time" id="saveName" class="form-control"></input>
|
||||
|
@ -42,6 +42,19 @@
|
||||
<!-- <button type="submit" id="sendWithCookie" style="margin-top: 10px" class="btn btn-primary">{{"Start Design with cookie data from local browser~带本地数据开始设计" | lang}}</button>-->
|
||||
<!-- </div>-->
|
||||
<div style="margin-top: 20px">
|
||||
<div v-if="mobile">
|
||||
<div v-if="language=='zh'">
|
||||
<p>提示:手机模式设计时如果没有出现操作提示框,请按键盘的Ctrl+Shift+I组合键(MacOS为Command+Option+I组合键)打开开发者工具,然后<b>双击</b>“切换设备”按钮,即可正常出现并使用操作提示框。</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>Tip: If the operation prompt box does not appear when designing in mobile mode, please press the
|
||||
Ctrl+Shift+I key combination (MacOS is the Command+Option+I key combination) to open the
|
||||
developer tool, and then <b>double-click</b> the "Toggle Device Toolbar" button, you can normally appear and use the operation toolbox.</p>
|
||||
</div>
|
||||
<img src="../img/toggle.png" alt="" style="width: 100%;height: 100%">
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<h5>{{"Example 1~示例1" | lang}}</h5>
|
||||
<p>{{"(Right click) Select a large product block -> Click the 'Select All' option -> Click the 'Select Child Elements' option -> Click the 'Collect Data' option, you can collect the information of all products, and will be saved by sub-field. ~ (右键)选中一个大商品块 -> 自动检测到同类型商品块 -> 点击“选中全部”选项 -> 点击“选中子元素”选项 -> 点击“采集数据”选项,即可采集到所有商品的所有信息,并分成不同字段保存。" | lang}}</p>
|
||||
<img src="../img/animation_zh.gif" alt="" style="width: 100%;height: 100%">
|
||||
@ -54,17 +67,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<script src="global.js"></script>
|
||||
<script>
|
||||
var app = new Vue({
|
||||
let app = new Vue({
|
||||
el: '#newTask',
|
||||
data: {
|
||||
backEndAddressServiceWrapper: getUrlParam("backEndAddressServiceWrapper"),
|
||||
user_data_folder: "",
|
||||
mobile: getUrlParam("mobile"),
|
||||
language: getUrlParam("lang"),
|
||||
},
|
||||
methods: {
|
||||
gotoHome: function () {
|
||||
|
@ -50,7 +50,7 @@
|
||||
<p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">{{"Create Time:~创建时间:" | lang}} {{dateFormat(task["create_time"])}}</p>
|
||||
<p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">{{"Update Time:~更新时间:" | lang}} {{dateFormat(task["update_time"])}}</p>
|
||||
<p>{{"Operations (Please close this window and select 'Design Task' button if you want to modify task with a browser)~操作(如要带浏览器修改任务流程请关闭此窗口并选择设计任务)" | lang}}</p>
|
||||
<p><a style="margin-top: 5px" href="javascript:void(0)" v-on:click="modifyTask(task['id'],task['url'])" class="btn btn-primary">{{"Modify Task Workflow~修改任务流程" | lang}}</a>
|
||||
<p><a style="margin-top: 5px" href="javascript:void(0)" v-on:click="modifyTask(task['id'],task['url'])" class="btn btn-primary">{{"Modify Task~修改任务" | lang}}</a>
|
||||
<a style="margin-top: 5px" href="javascript:void(0)" v-on:click="invokeTask(task['id'],task['url'])" class="btn btn-primary">{{"Execute Task~执行任务" | lang}}</a></p>
|
||||
<p>{{"Input Parameters~输入参数" | lang}}</p>
|
||||
<table class="table table-bordered">
|
||||
|
1
ElectronJS/tasks/296.json
Normal file
1
ElectronJS/tasks/296.json
Normal file
@ -0,0 +1 @@
|
||||
{"id":296,"name":"知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具","url":"https://www.zsxq.com","links":"https://wx.zsxq.com/dweb2/index/group/48844244282448","create_time":"12/18/2023, 3:49:05 PM","update_time":"12/18/2023, 4:12:12 PM","version":"0.6.0","saveThreshold":10,"quitWaitTime":60,"environment":0,"maximizeWindow":0,"maxViewLength":15,"recordLog":1,"outputFormat":"xlsx","saveName":"current_time","dataWriteMode":1,"inputExcel":"","startFromExit":0,"pauseKey":"p","containJudge":false,"browser":"chrome","desc":"https://www.zsxq.com","inputParameters":[{"id":0,"name":"urlList_0","nodeId":1,"nodeName":"打开网页","value":"https://wx.zsxq.com/dweb2/index/group/48844244282448","desc":"要采集的网址列表,多行以\\n分开","type":"text","exampleValue":"https://wx.zsxq.com/dweb2/index/group/48844244282448"}],"outputParameters":[],"graph":[{"index":0,"id":0,"parentId":0,"type":-1,"option":0,"title":"root","sequence":[1,2,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":"打开网页","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.zsxq.com","links":"https://wx.zsxq.com/dweb2/index/group/48844244282448","maxWaitTime":10,"scrollType":0,"scrollCount":1,"scrollWaitTime":1,"cookies":""}},{"id":2,"index":2,"parentId":0,"type":0,"option":2,"title":"点击【腾讯研究院...","sequence":[],"isInLoop":false,"position":1,"parameters":{"history":8,"tabIndex":-1,"useLoop":false,"xpath":"//*[contains(@class, \"group-file-container\")]/div[2]/div[1]/div[2]","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,"newTab":0,"maxWaitTime":10,"params":[],"alertHandleType":0,"allXPaths":["/html/body/app-root[1]/app-index[1]/div[1]/app-topic-flow[1]/div[1]/app-group-preview[1]/div[1]/div[1]/app-group-file[1]/div[1]/div[2]/div[1]/div[2]","//div[contains(., '【腾讯研究院】全真互')]","//DIV[@class='file-name']","/html/body/app-root/app-index/div/app-topic-flow/div/app-group-preview/div/div/app-group-file/div/div/div[last()-2]/div"]}},{"id":3,"index":3,"parentId":0,"type":0,"option":2,"title":"点击文件详情\n查...","sequence":[],"isInLoop":false,"position":2,"parameters":{"history":8,"tabIndex":-1,"useLoop":false,"xpath":"point(100, 10)","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,"newTab":0,"maxWaitTime":10,"params":[],"alertHandleType":0,"allXPaths":["/html/body/app-root[1]/app-index[1]/div[1]/app-topic-flow[1]/div[1]/app-file-preview[1]/div[1]","//div[contains(., '文件详情查看原主题本')]","//DIV[@class='file-preview-container']","/html/body/app-root/app-index/div/app-topic-flow/div/app-file-preview/div"]}}]}
|
2
ExecuteStage/.vscode/launch.json
vendored
2
ExecuteStage/.vscode/launch.json
vendored
@ -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", "[28]", "--headless", "0", "--user_data", "0", "--keyboard", "0",
|
||||
"args": ["--ids", "[61]", "--headless", "0", "--user_data", "0", "--keyboard", "0",
|
||||
"--read_type", "remote"]
|
||||
// "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"
|
||||
}
|
||||
|
@ -466,9 +466,9 @@ class BrowserThread(Thread):
|
||||
def run(self):
|
||||
# 挨个执行程序
|
||||
for i in range(len(self.links)):
|
||||
self.print_and_log("正在执行第", i + 1, "/ ", len(self.links), "个链接")
|
||||
self.print_and_log("正在执行第", i + 1, "/", len(self.links), "个链接")
|
||||
self.print_and_log("Executing link", i + 1,
|
||||
"/ ", len(self.links))
|
||||
"/", len(self.links))
|
||||
self.executeNode(0)
|
||||
self.urlId = self.urlId + 1
|
||||
files = os.listdir("Data/Task_" + str(self.id) + "/" + self.saveName)
|
||||
@ -1208,7 +1208,7 @@ class BrowserThread(Thread):
|
||||
if len(elements) == 0:
|
||||
self.print_and_log("Loop element not found: ",
|
||||
xpath)
|
||||
self.print_and_log("找不到循环元素: ", xpath)
|
||||
self.print_and_log("找不到循环元素:", xpath)
|
||||
index = 0
|
||||
while index < len(elements):
|
||||
try:
|
||||
@ -1258,7 +1258,7 @@ class BrowserThread(Thread):
|
||||
index = index + 1
|
||||
except NoSuchElementException:
|
||||
self.print_and_log("Loop element not found: ", xpath)
|
||||
self.print_and_log("找不到循环元素: ", xpath)
|
||||
self.print_and_log("找不到循环元素:", xpath)
|
||||
except Exception as e:
|
||||
raise
|
||||
elif int(node["parameters"]["loopType"]) == 2: # 固定元素列表
|
||||
@ -1303,7 +1303,7 @@ class BrowserThread(Thread):
|
||||
index, element = self.handleHistory(node, path, thisHistoryURL, thisHistoryLength, index, element=element)
|
||||
except NoSuchElementException:
|
||||
self.print_and_log("Loop element not found: ", path)
|
||||
self.print_and_log("找不到循环元素: ", path)
|
||||
self.print_and_log("找不到循环元素:", path)
|
||||
index += 1
|
||||
continue # 循环中找不到元素就略过操作
|
||||
except Exception as e:
|
||||
@ -1533,7 +1533,10 @@ class BrowserThread(Thread):
|
||||
clickPath, self.outputParameters, self)
|
||||
xpath = replace_field_values(
|
||||
param["xpath"], self.outputParameters, self)
|
||||
if param["useLoop"]: # 使用循环的情况下,传入的clickPath就是实际的xpath
|
||||
if xpath.find("point(") >= 0: # 如果xpath中包含point(),说明是相对坐标的点击
|
||||
index = 0
|
||||
path = "//body"
|
||||
elif param["useLoop"]: # 使用循环的情况下,传入的clickPath就是实际的xpath
|
||||
if xpath == "":
|
||||
path = clickPath
|
||||
else:
|
||||
@ -1567,7 +1570,19 @@ class BrowserThread(Thread):
|
||||
except:
|
||||
newTab = 0
|
||||
try:
|
||||
if click_way == 0: # 用selenium的点击方法
|
||||
if xpath.find("point(") >= 0: # 如果xpath中包含point(),说明是相对坐标的点击
|
||||
point = xpath.split("point(")[1].split(")")[0].split(",")
|
||||
x = int(point[0])
|
||||
y = int(point[1])
|
||||
# try:
|
||||
# actions = ActionChains(self.browser) # 实例化一个action对象
|
||||
# actions.move_to_element(element).perform()
|
||||
# actions.move_by_offset(x, y).perform()
|
||||
# actions.click().perform()
|
||||
# except Exception as e:
|
||||
script = "document.elementFromPoint(" + str(x) + "," + str(y) + ").click();"
|
||||
self.browser.execute_script(script)
|
||||
elif click_way == 0: # 用selenium的点击方法
|
||||
try:
|
||||
actions = ActionChains(self.browser) # 实例化一个action对象
|
||||
if newTab == 1: # 在新标签页打开
|
||||
|
@ -9,8 +9,8 @@ import time
|
||||
import uuid
|
||||
# import keyboard
|
||||
from openpyxl import Workbook, load_workbook
|
||||
import pandas as pd
|
||||
import xlsxwriter
|
||||
# import pandas as pd
|
||||
# import xlsxwriter
|
||||
import requests
|
||||
from urllib.parse import urlparse
|
||||
import pymysql
|
||||
|
@ -320,3 +320,7 @@ let closeButton = document.getElementById("closeButton");
|
||||
closeButton.addEventListener("click", function() {
|
||||
toolkit.style.display = "none"; // 隐藏元素
|
||||
});
|
||||
let closeButtonLeft = document.getElementById("closeButtonLeft");
|
||||
closeButtonLeft.addEventListener("click", function() {
|
||||
toolkit.style.display = "none"; // 隐藏元素
|
||||
});
|
||||
|
@ -3,6 +3,7 @@
|
||||
<!-- <div id="EasySpiderResizer" style="width: 10px; height: 10px; background-color: black; position: absolute; left: 0; bottom: 0; cursor: ne-resize;"></div>-->
|
||||
<div id="EasySpiderResizer"
|
||||
style="width: 10px; height: 10px; position: absolute; left: 0; top: 0; cursor: nw-resize;"></div>
|
||||
<span id="closeButtonLeft">✖</span>
|
||||
<span id="closeButton">✖</span>
|
||||
<div v-if="lang == 'zh'">
|
||||
<div class="tooldrag">✍操作台(点此拖动,左上角调整大小)</div>
|
||||
@ -33,7 +34,7 @@
|
||||
<p style="color:black; margin-top: 10px">● 操作完成后,如点击”确认采集“后任务流程图内没有”提取数据“操作被添加,<strong>重试一次</strong>即可。
|
||||
</p>
|
||||
<p style="color:black; margin-top: 10px">●
|
||||
如果此操作台把页面元素挡住了,可以点击此操作台右下角的×按钮键关闭操作台。</p>
|
||||
如果此操作台把页面元素挡住了,可以点击此操作台左下角或右下角的×按钮键关闭操作台。</p>
|
||||
{{ initial() }}
|
||||
</div>
|
||||
<div v-if="list.nl.length==1">
|
||||
@ -243,7 +244,7 @@
|
||||
again.</p>
|
||||
<p style="color:black; margin-top: 10px">● If this toolbox blocks the page element, you can click the ×
|
||||
button in the
|
||||
lower right corner of this toolbox to close it.</p>
|
||||
lower left/right corner of this toolbox to close it.</p>
|
||||
{{ initial() }}
|
||||
</div>
|
||||
<div v-if="list.nl.length==1">
|
||||
|
@ -188,11 +188,23 @@
|
||||
#closeButton {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
right: 4px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
opacity: 0.05;
|
||||
opacity: 0.2;
|
||||
}
|
||||
#closeButton:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
#closeButtonLeft {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 4px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
opacity: 0.2;
|
||||
}
|
||||
#closeButtonLeft:hover {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user