auto-chrome
Advanced tools
Comparing version 1.2.6 to 1.2.7
@@ -208,4 +208,2 @@ "use strict"; | ||
this.page.title = targetInfo.title; | ||
} | ||
@@ -212,0 +210,0 @@ |
@@ -11,134 +11,173 @@ "use strict"; | ||
class Element { | ||
/** | ||
* @param {Function} page page实例 | ||
* @param {Object} remote 节点远程对象 | ||
*/ | ||
constructor(page, remote) { | ||
/** | ||
* @param {Function} page page实例 | ||
* @param {Object} remote 节点远程对象 | ||
*/ | ||
constructor(page, remote) { | ||
this.page = page; | ||
this.page = page; | ||
this.frame = page.frame; | ||
this.frame = page.frame; | ||
if (remote) { | ||
if (remote) { | ||
const { objectId, description, className } = remote; | ||
const { objectId, description, className } = remote; | ||
this.objectId = objectId; | ||
this.description = description; | ||
this.className = className; | ||
this.objectId = objectId; | ||
this.description = description; | ||
this.className = className; | ||
} | ||
} | ||
} | ||
/** | ||
* 创建新的Element实例 | ||
* @param {Object} remote 远程资源对象 | ||
*/ | ||
create(remote) { | ||
} | ||
/** | ||
* 创建新的Element实例 | ||
* @param {Object} remote 远程资源对象 | ||
*/ | ||
create(remote) { | ||
return new Element(this.page, remote); | ||
return new Element(this.page, remote); | ||
} | ||
/** | ||
* CSS单选迭代选择器 | ||
* @param {String} selector | ||
*/ | ||
async $(selector) { | ||
} | ||
/** | ||
* CSS单选迭代选择器 | ||
* @param {String} selector | ||
*/ | ||
async $(selector) { | ||
const { objectId } = this; | ||
const { objectId } = this; | ||
const remote = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element = document, selector) => { | ||
// console.log(element); | ||
// console.log(selector); | ||
return element.querySelector(selector); | ||
}, | ||
arguments: [{ objectId }, { value: selector }] | ||
}); | ||
const remote = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element = document, selector) => { | ||
// console.log(element); | ||
// console.log(selector); | ||
return element.querySelector(selector); | ||
}, | ||
arguments: [{ objectId }, { value: selector }] | ||
}); | ||
const { className, description } = remote; | ||
const { className, description } = remote; | ||
if (className === 'TypeError') { | ||
if (className === 'TypeError') { | ||
consoln.warn(new Error(description)); | ||
consoln.warn(new Error(description)); | ||
return | ||
return | ||
} | ||
} | ||
if (remote.objectId) { | ||
if (remote.objectId) { | ||
return this.create(remote); // 创建新的远程子节点实例 | ||
return this.create(remote); // 创建新的远程子节点实例 | ||
} | ||
} | ||
} | ||
/** | ||
* CSS多选迭代选择器 | ||
* @param {String} selector | ||
*/ | ||
async $$(selector) { | ||
} | ||
/** | ||
* CSS多选迭代选择器 | ||
* @param {String} selector | ||
*/ | ||
async $$(selector) { | ||
const { objectId } = this; | ||
const { objectId } = this; | ||
const remote = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element = document, selector) => { | ||
return element.querySelectorAll(selector) | ||
}, | ||
arguments: [{ objectId }, { value: selector }] | ||
}); | ||
const remote = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element = document, selector) => { | ||
return element.querySelectorAll(selector) | ||
}, | ||
arguments: [{ objectId }, { value: selector }] | ||
}); | ||
const { className, description } = remote; | ||
const { className, description } = remote; | ||
if (className === 'TypeError') { | ||
consoln.warn(new Error(description)); | ||
return | ||
if (className === 'TypeError') { | ||
consoln.warn(new Error(description)); | ||
return | ||
} | ||
if (remote.objectId) { | ||
const { result } = await this.page.send('Runtime.getProperties', { | ||
objectId: remote.objectId, | ||
"ownProperties": true | ||
}) | ||
const elements = []; | ||
// 批量创建子节点实例 | ||
for (const item of result) { | ||
const { enumerable, value } = item; | ||
if (enumerable === true) { | ||
const element = this.create(value); | ||
elements.push(element); | ||
} | ||
} | ||
if (remote.objectId) { | ||
elements.objectId = remote.objectId; | ||
const { result } = await this.page.send('Runtime.getProperties', { | ||
objectId: remote.objectId, | ||
"ownProperties": true | ||
}) | ||
return elements; | ||
const elements = []; | ||
} | ||
// 批量创建子节点实例 | ||
for (const item of result) { | ||
} | ||
/** | ||
* 取值 | ||
* @param {string} path 对象路径,仅支持“.”对象表达式,不支持“[index]”数组 | ||
*/ | ||
async get(path) { | ||
const { enumerable, value } = item; | ||
const { objectId } = this; | ||
if (enumerable === true) { | ||
const element = this.create(value); | ||
elements.push(element); | ||
} | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element, path) => { | ||
const pathArray = path.split('.'); | ||
let iterate = element; | ||
for (const item of pathArray) { | ||
iterate = iterate[item]; | ||
} | ||
return iterate; | ||
}, | ||
arguments: [{ objectId }, { value: path }] | ||
}) | ||
} | ||
return result.value; | ||
elements.objectId = remote.objectId; | ||
} | ||
/** | ||
* 设置值 | ||
* @param {String} name 属性名称 | ||
* @param {*} value 属性值 | ||
*/ | ||
async set(name, value) { | ||
return elements; | ||
const { objectId } = this; | ||
} | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element, name, value) => { | ||
return element[name] = value; | ||
}, | ||
arguments: [{ objectId }, { value: name }, { value }] | ||
}) | ||
} | ||
/** | ||
* 取值 | ||
* @param {string} path 对象路径,仅支持“.”对象表达式,不支持“[index]”数组 | ||
*/ | ||
async get(path) { | ||
return result.value; | ||
const { objectId } = this; | ||
} | ||
/** | ||
* 获取或设置值,仅适用于input元素 | ||
* @param {*} value 赋值 | ||
*/ | ||
async value(value) { | ||
const { objectId } = this; | ||
if (value) { | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element, path) => { | ||
const pathArray = path.split('.'); | ||
let iterate = element; | ||
for (const item of pathArray) { | ||
iterate = iterate[item]; | ||
} | ||
return iterate; | ||
}, | ||
arguments: [{ objectId }, { value: path }] | ||
functionDeclaration: (element, value) => { | ||
return element.value = value | ||
}, | ||
arguments: [{ objectId }, { value }] | ||
}) | ||
@@ -148,17 +187,7 @@ | ||
} | ||
/** | ||
* 设置值 | ||
* @param {String} name 属性名称 | ||
* @param {*} value 属性值 | ||
*/ | ||
async set(name, value) { | ||
} else { | ||
const { objectId } = this; | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element, name, value) => { | ||
return element[name] = value; | ||
}, | ||
arguments: [{ objectId }, { value: name }, { value }] | ||
functionDeclaration: element => element.value, | ||
arguments: [{ objectId }] | ||
}) | ||
@@ -168,175 +197,171 @@ | ||
} | ||
/** | ||
* 获取或设置值,仅适用于input元素 | ||
* @param {*} value 赋值 | ||
*/ | ||
async value(value) { | ||
} | ||
const { objectId } = this; | ||
} | ||
/** | ||
* 键盘输入 | ||
* @param {*} text 输入文本 | ||
* @param {*} options 附加选项 | ||
*/ | ||
async type(text, options) { | ||
if (value) { | ||
return await this.page.keyboard.type(text, options) | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: (element, value) => { | ||
return element.value = value | ||
}, | ||
arguments: [{ objectId }, { value }] | ||
}) | ||
} | ||
/** | ||
* 获取元素坐标信息 | ||
*/ | ||
async getBoundingRect() { | ||
return result.value; | ||
const { objectId } = this; | ||
} else { | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
const { x, y, width, height } = element.getBoundingClientRect(); | ||
const { innerHeight, innerWidth } = window; | ||
return { | ||
x, | ||
y, | ||
width, | ||
height, | ||
innerHeight, | ||
innerWidth | ||
} | ||
}, | ||
arguments: [{ objectId }], | ||
returnByValue: true | ||
}); | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: element => element.value, | ||
arguments: [{ objectId }] | ||
}) | ||
return result.value; | ||
return result.value; | ||
} | ||
} | ||
/** | ||
* 分多次滚动页面至目标元素可视区域 | ||
* 在每个单次滚动后重新计数坐标,防止DOM更新后原坐标失效 | ||
* 当chrome不稳定导致事件未执行时,采用实时坐标提供了纠正错误的机会 | ||
*/ | ||
async scroll() { | ||
} | ||
/** | ||
* 键盘输入 | ||
* @param {*} text 输入文本 | ||
* @param {*} options 附加选项 | ||
*/ | ||
async type(text, options) { | ||
const bounding = await this.getBoundingRect(); | ||
return await this.page.keyboard.type(text, options) | ||
const isNext = await this.page.clicker.scrollBounding(bounding); | ||
} | ||
/** | ||
* 获取元素坐标信息 | ||
*/ | ||
async getBoundingRect() { | ||
// 返回值next为true时表继续递归 | ||
if (isNext === true) { | ||
const { objectId } = this; | ||
await this.scroll(); | ||
const result = await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
const { x, y, width, height } = element.getBoundingClientRect(); | ||
const { innerHeight, innerWidth } = window; | ||
return { | ||
x, | ||
y, | ||
width, | ||
height, | ||
innerHeight, | ||
innerWidth | ||
} | ||
}, | ||
arguments: [{ objectId }], | ||
returnByValue: true | ||
}); | ||
} | ||
return result.value; | ||
} | ||
} | ||
/** | ||
* 快速将元素滚动至可视区域 | ||
*/ | ||
async scrollIntoView() { | ||
/** | ||
* 分多次滚动页面至目标元素可视区域 | ||
* 在每个单次滚动后重新计数坐标,防止DOM更新后原坐标失效 | ||
* 当chrome不稳定导致事件未执行时,采用实时坐标提供了纠正错误的机会 | ||
*/ | ||
async scroll() { | ||
const { objectId } = this; | ||
const bounding = await this.getBoundingRect(); | ||
await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
element.scrollIntoView(); | ||
}, | ||
arguments: [{ objectId }] | ||
}) | ||
const isNext = await this.page.clicker.scrollBounding(bounding); | ||
await sleep(600); | ||
// 返回值next为true时表继续递归 | ||
if (isNext === true) { | ||
} | ||
await this.scroll(); | ||
/** | ||
* 仿真点击元素 | ||
*/ | ||
async click() { | ||
} | ||
// await this.label() | ||
} | ||
const result = await this.getBoundingRect(); | ||
/** | ||
* 快速将元素滚动至可视区域 | ||
*/ | ||
async scrollIntoView() { | ||
let { x, y, width, height } = result; | ||
const { objectId } = this; | ||
// 定位到元素中心 | ||
x = x + width / 2; | ||
y = y + height / 2; | ||
await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
element.scrollIntoView(); | ||
}, | ||
arguments: [{ objectId }] | ||
}) | ||
await this.page.clicker.click(x, y); | ||
await sleep(600); | ||
return result; | ||
} | ||
} | ||
/** | ||
* 带导航的仿真点击元素 | ||
* @param {number} time 导航限时 | ||
*/ | ||
async clickNav(time = 3000) { | ||
/** | ||
* 高仿真点击元素 | ||
*/ | ||
async click() { | ||
const result = await this.getBoundingRect(); | ||
// await this.label() | ||
let { x, y, width, height } = result; | ||
const result = await this.getBoundingRect(); | ||
// 定位到元素中心 | ||
x = x + width / 2; | ||
y = y + height / 2; | ||
let { x, y, width, height } = result; | ||
await Promise.all([ | ||
this.page.chrome.autoNav(time), | ||
this.page.clicker.click(x, y) | ||
]).catch(error => { | ||
consoln.error(error); | ||
throw error; | ||
}) | ||
// 定位到元素中心 | ||
x = x + width / 2; | ||
y = y + height / 2; | ||
return result; | ||
await this.page.clicker.click(x, y); | ||
return result; | ||
} | ||
/** | ||
* 高仿真点击元素,带导航 | ||
} | ||
/** | ||
* 直接在Dom上调用click()方法,触发点击事件 | ||
*/ | ||
async clickNav(time = 3000) { | ||
async clickDom({ target = true }) { | ||
const result = await this.getBoundingRect(); | ||
const { objectId } = this; | ||
let { x, y, width, height } = result; | ||
await Promise.all([ | ||
this.frame.callFunctionOn({ | ||
functionDeclaration: (element, target) => { | ||
if (target) { | ||
element.target = "_blank"; | ||
} | ||
element.click(); | ||
}, | ||
arguments: [{ objectId }, { value: target }] | ||
}), | ||
this.page.chrome.autoNav() | ||
]).catch(error => { | ||
consoln.error(error); | ||
throw error; | ||
}); | ||
// 定位到元素中心 | ||
x = x + width / 2; | ||
y = y + height / 2; | ||
} | ||
await Promise.all([ | ||
this.page.chrome.autoNav(time), | ||
this.page.clicker.click(x, y) | ||
]).catch(error => { | ||
consoln.error(error); | ||
throw error; | ||
}) | ||
/** | ||
* 框选元素 | ||
*/ | ||
async label() { | ||
return result; | ||
const { objectId } = this; | ||
} | ||
await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
element.style.border = "1px solid #ed0000" | ||
}, | ||
arguments: [{ objectId }] | ||
}) | ||
/** | ||
* 框选元素 | ||
*/ | ||
async label() { | ||
await sleep(500); | ||
const { objectId } = this; | ||
} | ||
await this.frame.callFunctionOn({ | ||
functionDeclaration: element => { | ||
element.style.border = "1px solid #ed0000" | ||
}, | ||
arguments: [{ objectId }] | ||
}) | ||
await sleep(500); | ||
} | ||
} | ||
module.exports = Element; |
@@ -80,2 +80,2 @@ "use strict"; | ||
module.exports = Frame; | ||
module.exports = Frame; |
@@ -12,3 +12,2 @@ "use strict"; | ||
class Page extends PageEvent { | ||
constructor(chrome, targetId) { | ||
@@ -323,2 +322,2 @@ | ||
module.exports = Page; | ||
module.exports = Page; |
{ | ||
"name": "auto-chrome", | ||
"version": "1.2.6", | ||
"version": "1.2.7", | ||
"description": "使用Node.js操作Chrome或Chromium,高仿真的用户行为模拟器", | ||
@@ -5,0 +5,0 @@ "main": "lib/", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
87144
2058