Javascript无法将Vars / Fn传递给.evaluate()范围(NightmareJS)

时间:2017-09-29 23:35:31

标签: javascript async-await nightmare

我正在尝试将变量传递给.evaluate,因此我可以在网页范围内使用它们,但我无法让它工作。

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    })

    .evaluate(function(result) {
        for(var i = 0; i < result.length; i++) {
            var matchResult = result[i].match(/.com\/(.*?)\?fref/);
            if (matchResult) {
                console.log(matchResult[1]);
            }
        }
    });

为此,我得到Cannot read property 'match' of undefined。然后我尝试了:

const evaluated = await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    });

    await nightmare.evaluate(function(evaluated) {
        for(var i = 0; i < evaluated.length; i++) {
            var matchResult = evaluated[i].match(/.com\/(.*?)\?fref/);
            if (matchResult) {
                console.log(matchResult[1]);
            }
        }
    });

结果相同。然后我尝试了:

const evaluated = await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    });

for(var i = 0; i < evaluated.length; i++){
        var matchResult = evaluated[i].match(/.com\/(.*?)\?fref/);
        if(matchResult) {
            console.log(matchResult[1]);
            await nightmare.evaluate(function(matchResult) {
                return document.body.innerHTML += '<a href="https://www.example.com/'+matchResult[0]+'">'+matchResult[0]+'</a>';
            });
            await nightmare.click('a[href="https://www.example.com/'+matchResult[0]+'"]');
            await nightmare.wait(5000);
        }
    }
await nightmare.end();

为此,执行循环的第一次迭代,并将matchResult[1]记录到控制台。然后我得到Error: Evaluation timed out after 30000msec. Are you calling done() or resolving your promises?

我也试过这样的事情:

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    }).then(function(users){

    }).end();

哪个确实将返回值传递给.then()但是如何将数组传递给下一个评估?现在这是我能想到的最后一件事,但不起作用:

await nightmare.evaluate(function() {
        let links = document.querySelectorAll('div.fsl a');
        return Array.prototype.map.call(links, function(e) {
            return e.getAttribute('href');
        });
    }).evaluate((users) => {
        console.log(users);
    }).end();

我找到了解决方案here,但它为我返回undefined。我还发现this在PhantomJS中讨论了类似的事情,但还没有提出可行的代码。

1 个答案:

答案 0 :(得分:1)

我找到了答案。似乎有一半的尝试可能正在发挥作用,我只是没有意识到这一点。在.evaluate()的范围内,我们处于浏览器范围内(按预期),但我没有考虑到我无法从该范围登录到控制台。具体来说,我无法登录到我的控制台。如果我从该范围运行console.log,它将登录到浏览器控制台。以下代码有效:

    var foo = "stuff";
    var bar = "stuff for the remote page";

    var result = await nightmare.evaluate(function(bar2) {
        // this function executes in the remote context
        // it has access to the DOM, remote libraries, and args you pass in
        console.log("bla "+bar2); // this will not output
        // but not to outer-scope vars
        return typeof foo + " " + bar2;
    }, bar);
    console.log(result); // this logs bar2!

我认为这解决了它。调试文档范围内发生的事情可能有点棘手,但肯定是可能的。