在数组上循环以尝试页面上的多个选项,并在每次迭代时返回到初始页面

Loop over an array to try multiple options on a page and come back to that initial page for each iteration

本文关键字:迭代 返回 循环 数组 选项      更新时间:2023-09-26

我正在使用CasperJS从网站上抓取一些数据。在主页上,有一个下拉列表,其中列出了所有50个州。该值是2个字母的缩写。

var states;
casper.start(url);
casper.then(function() {
    states = this.evaluate(function getOptionVals() {
        // loop thru and get the values
        return arrayValues;
    });
});

接下来,我想循环浏览缩写数组,然后在同一页上填充一些元素。页面上没有表单,只有一些单选按钮和一个提交按钮。

提交按钮导航到一个新的.asp页面,该页面将搜索选项作为查询字符串参数传递

casper.then(function () {
    // loop over all states
    this.eachThen(states,function(state) {
        this.echo('state = ' + state.data);
        // step 1
        this.evaluate(function(state) {
            console.log('In .evaluate the state is '+state);
            // select the radio button
            $('#searchoption1').prop('checked',true);
            $('#searchoption2').prop('checked',false);
            $('#showall').prop('checked',true);
            // select the State from the dropdown
            $('#state option[value="'+state+'"]').prop('selected', true);
            $('#submit1').click();
        },state.data); // pass in the array from the first casper.then call
        // step 2
        this.waitForSelector('table.mainTable tbody table  tbody blockquote',function() {
            this.evaluate(function(){
                console.log($('table.mainTable h1 ').text());
            });
        });
    })
});
casper.run();

我的问题是CasperJS的异步性。当我运行它时,console.log()会报告每次通过循环时数组中第一个状态的结果。对于第2步,我尝试了很多不同的方法(来自SO上的帖子),但都无济于事。

如何让循环等待步骤2完成后再继续?

输出如下:

start step #1 get state abbreviations
start #2 loop over all states
state = AL
In .evaluate the state is AL
loc: (/Find_Range/wts_subresults_test.asp)
dir2: (e)
Ranges for the State/Province of Alabama
state = AK
In .evaluate the state is AK
Ranges for the State/Province of Alabama
state = AZ
In .evaluate the state is AZ
Ranges for the State/Province of Alabama
state = AR
In .evaluate the state is AR
Ranges for the State/Province of Alabama
state = CA
In .evaluate the state is CA
Ranges for the State/Province of Alabama
state = CO
In .evaluate the state is CO
Ranges for the State/Province of Alabama
state = CT
In .evaluate the state is CT
Ranges for the State/Province of Alabama

因此,this.evaluatethis.waitForSelector函数并不是在浏览器上下文中"找到"正确的页面。我希望输出看起来像:

In .evaluate the state is AL
loc: (/Find_Range/wts_subresults_test.asp)
dir2: (e)
Ranges for the State/Province of Alabama
state = AK
In .evaluate the state is AK
Ranges for the State/Province of Alaska
state = AZ
In .evaluate the state is AZ
Ranges for the State/Province of Arizona
state = AR
In .evaluate the state is AR
Ranges for the State/Province of Arkansas
state = CA
In .evaluate the state is CA
Ranges for the State/Province of California
state = CO
In .evaluate the state is CO
Ranges for the State/Province of colorado

所以每次通过这个。每个都应该导航回步骤2后的第一页。

单击提交按钮导航到另一个页面,但问题似乎是您在eachThen的下一次迭代中不再处于初始页面:

因此,每次通过this.each都应该导航回步骤2之后的第一页。

此时您有两个选项:

1.在每次迭代中打开您开始时所在的页面:

casper.then(function () {
    var url = this.getCurrentUrl();
    // loop over all states
    this.eachThen(states, function(state) {
        this.echo('state = ' + state.data);
        // step 0
        this.thenOpen(url);
        // step 1
        this.thenEvaluate(...);
        // step 2
        this.waitForSelector(...);
    })
});

注意,我使用了thenEvaluate而不是evaluate,因为像evaluate这样的同步函数调用不应该跟在像thenOpen这样的异步步进函数调用之后。

2.返回:

casper.then(function () {
    // loop over all states
    this.eachThen(states, function(state) {
        this.echo('state = ' + state.data);
        // step 1
        this.thenEvaluate(...);
        // step 2
        this.waitForSelector(...);
        // step 3
        this.back();
    })
});

请注意,您可能需要使用back两次(或两次以上):this.back().back();,因为有时会有重定向,PhantomJS不会在一步中进入预重定向页面。


如果您使用CasperJS进行导航,那么通常只有一个page实例。当你点击某个东西并创建一个新的窗口/弹出窗口时,可以创建额外的页面实例,但这里不是这样。

您看到不同的短状态名称,但始终是相同的长状态名称的原因是,states在您开始迭代之前就已填充,但在第一次迭代之后,您仍然在同一页上。

通过监听"page.error"事件,您可能已经注意到脚本的问题,该事件会向您显示无法找到某些元素(在第一次迭代后的evaluate内部):

casper.on("page.error", function(msg, trace) {
    this.echo("Error: " + msg);
    // maybe make it a little fancier with the code from the PhantomJS equivalent
});

此外,如果你想知道发生了什么,你应该在每一个有趣的地方截屏casper.capture(filename);