我的目标是系统地收集有关网页上每个元素的信息。具体来说,我想为每个元素执行el.getBoundingClientRect()
和window.getComputedStyle(el)
。
我一直在使用Selenium WebDriver for NodeJS加载页面并管理浏览器交互。为简化起见,我们只关注getComputedStyle
:
driver.findElements(By.xpath("//*"))
.then(elements => {
var elementsLeft = elements.length;
console.log('Entering async map');
async.map(elements, el => {
driver.executeScript("return window.getComputedStyle(arguments[0]).cssText",el)
.then((styles: any) => {
//stuff would be done here with the styles
console.log(elements.indexOf(el));
});
});
});
此代码将遍历所有元素并检索其样式,但非常慢。页面可能需要几分钟才能完成。我希望驱动程序异步执行脚本,但这似乎不可能,因为每个Selenium驱动程序都有一个' ControlFlow'确保驱动程序的每个命令仅在最后一个命令完成后启动。我需要找到一个解决方法,以便我可以在页面上异步执行javascript(并使我的数据收集更快)。
注意:我也尝试过Selenium的executeAsyncScript,它只是一个围绕executeScript的包装器,并且在它完成之前仍然会阻塞。这是我使用executeAsyncScript的代码 - 它的执行效果与前面的代码一样:
driver.findElements(By.xpath("//*"))
.then(elements => {
var elementsLeft = elements.length;
async.map(elements, el => {
driver.executeAsyncScript(
function(el: any) {
var cb = arguments[arguments.length - 1];
cb(window.getComputedStyle(el).cssText);
}, el)
.then((styles: any) => {
//stuff would be done here with the styles
console.log(elements.indexOf(el));
});
});
});
我正在寻找一种方法来绕过Selenium的ControlFlow,以便异步执行我的javascript,找到一种方法来提取对象而不受驱动程序的约束,或找到替代工具/解决方案获取我需要的数据。
答案 0 :(得分:0)
由于executeScript
可以接收WebElement
,您是否看到在一次通话中完成所有工作而不是反复拨打executeScript
是否更快?
driver.findElements(By.xpath("//*"))
.then(elements => {
driver.executeScript("return arguments[0].map(function(el) {return [el, window.getComputedStyle(el).cssText];})", elements)
.then((styles: any) => {
//stuff would be done here with the styles
console.log(styles);
});
});
});
如果这太慢了,你是否考虑在脚本中找到所有元素而不是传入它们?
driver.findElements(By.xpath("//*"))
.then(elements => {
driver.executeScript("return Array.prototype.slice.call(document.getElementsByTagName('*'))" +
".map(function(el) {return [el, window.getComputedStyle(el).cssText];})", elements)
.then((styles: any) => {
//stuff would be done here with the styles
console.log(styles);
});
});
});