通过Web驱动程序异步执行Javascript

时间:2016-05-04 19:18:45

标签: javascript node.js asynchronous selenium-webdriver webdriver

我的目标是系统地收集有关网页上每个元素的信息。具体来说,我想为每个元素执行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,找到一种方法来提取对象而不受驱动程序的约束,或找到替代工具/解决方案获取我需要的数据。

1 个答案:

答案 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);
            });
    });
});