循环并单击带有PhantomJS的querySelectorAll列表

时间:2014-11-06 16:13:46

标签: javascript dom phantomjs selectors-api

考虑以下(工作)PhantomJS代码段,应该点击类whatever的第一个元素:

page.evaluate(
    function()  
    {
        var a = document.querySelector(".whatever");
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        a.dispatchEvent(e);
        waitforload = true;
    }
);

我没有在类whatever的所有元素上循环 - 问题当然不是循环本身,而是访问querySelectorAll元素。

我被困在这里(我通过访问第一个元素来替换循环以便于调试;当然,必须有两个page.evaluate调用,因为第二个元素将在循环中):

var aa = page.evaluate(
    function()
    {
        return document.querySelectorAll(".whatever");
    }
)
//for (i=0; i<aa.length; i++)
//{
page.evaluate(
    function()  
    {
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
//      aa[i].dispatchEvent(e);
        aa[0].dispatchEvent(e);
        waitforload = true;
    }
);
//}

我尝试了多种变体,删除var,为document.添加前缀,尝试将aa作为参数传递等等。没有任何效果(我可能错过了 正确的组合,但无论如何我明显错过了这里的基础。)

我不确定它是否与命名空间和变量范围有关(我是JS的新手)或问题来自querySelectorAll输出(虽然我检查了数组的大小为了正确),因为我遇到了“ ReferenceError:找不到变量”和“ TypeError:'undefined'不是对象”错误。

欢迎任何提示。

1 个答案:

答案 0 :(得分:2)

根据您的comment

  

只需点击一下即可加载包含其他信息的框。盒子本身隐藏了其他按钮,因此我不知道在显示该框时单击另一个按钮会发生什么。我的猜测是,它将替换或替换上一个框。无论如何,我的目标是获得所有这些盒子。所以一开始我会尝试一个接一个地点击一切。

最简单的解决方案是检索.whatever元素的数量并根据它进行迭代,但由于它需要一些页面交互而PhantomJS是异步的,因此您需要使用一些框架来运行一个步骤另一个。可以使用async,或者为此脚本创建类似的内容。

function clickInPageContext(selector, index){
    page.evaluate(function(selector, index){
        index = index || 0;
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        var el = document.querySelectorAll(selector);
        el[index].dispatchEvent(e);
    }, selector, index);
}

var async = require("async"); // install async through npm
var selector = ".whatever";
var num = page.evaluate(function(sel){
    return document.querySelectorAll(sel).length;
}, selector);
var steps = [];
for (var i = 0; i < num; i++) {
    // the immediately invoked function looks bad, but is necessary,
    // because JS has function level scope and this is executed long 
    // after the loop has finished
    steps.push((function(i){
        return function(complete){
            clickInPageContext(selector, i);
            setTimeout(function(){
                clickInPageContext("someCloseButtonSelector"); // maybe also parametrized with i
                setTimeout(function(){
                    complete();
                }, 1000); // time to close
            }, 1000); // time to open
        };
    })(i));
}
async.series(steps, function(){
    console.log("DONE");
    phantom.exit();
});

此测试取决于.whatever元素的数量保持不变的前提。注意:async可以通过npm(本地)安装。并且可以在PhantomJS中使用。
另外,请参阅this question我做过类似的事情。