【问题标题】:Asynchronously execute Javascript through a web driver通过 Web 驱动程序异步执行 Javascript
【发布时间】:2016-05-05 04:14:33
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    既然executeScript 可以接听WebElements,你有没有发现一次调用完成所有工作比重复调用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);
                });
        });
    });
    

    【讨论】:

    • 是的!谢谢!我不知道为什么我没有想到这一点,但这很完美。我尝试了第一个代码块,它就像一个魅力。如果性能一直是个问题,也可以尝试第二个。这是我的第一个 stackoverflow 问题,在尝试了几个晚上之后,我终于决定注册并询问...感谢您提供的最佳体验! :)
    猜你喜欢
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 2018-01-13
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    相关资源
    最近更新 更多