CasperJS - 尝试通过循环填充下拉菜单时访问页面的内容

时间:2017-05-25 09:24:07

标签: javascript web-scraping casperjs

我正在尝试使用casperjs进行一些测试,这里的某些情况是:

  
      
  • 从下拉菜单中提取城市名称(已经完成)

  •   
  • 然后选择每个城市(casper.fill()),这将导致加载新内容   页面上的内容和网址更改,(成功,使用单个城市名称进行测试,失败,循环显示城市名称列表)

  •   
  • 进一步了解新加载的商品链接(新页面),

  •   
  • 最后,抓住每个页面的内容

  •   

我试图循环遍历城市列表并在每个周期中完成所有工作。但问题是CasperJs尝试立即为每个城市设置<option>字段值,而不执行循环内的其余代码:

casper.then(function() {

    var citiesLength = cities.length;

    for (var i = 0; i < citiesLength; i++) {

        this.fill('form.wpv-filter-form',{   //setting drop-down field value to the city names in order of the items in the array
            'city[]': cityNames[i]
        });

// Apparently the code below (to the end of the loop) doesn't get executed
        casper.thenEvaluate(function() {

// Here the url change is being checked to know when the new content is loaded:
            var regexString = '(\\?)(city)(\\[\\])(=)(' + cityNames[i] + ')&';
            var regex = new RegExp(regexString, "igm");

            this.waitForUrl(regex, function(){
                var name = this.getHTML('.kw-details-title');
                link = this.evaluate(getFirstItemLink); // for test, just getting the first item's link

                casper.open(link).then(function(){
                    this.echo("New Page is loaded......");
                    // Grab the single item contents
                });
            });

        });
    }

这是日志(缩短为3个城市):

[debug] [remote] Set "city[]" field value to city1
[info] [remote] attempting to fetch form element from selector: 'form.wpv-filter-form'
[debug] [remote] Set "city[]" field value to city2
[info] [remote] attempting to fetch form element from selector: 'form.wpv-filter-form'
[debug] [remote] Set "city[]" field value to city3
[info] [remote] attempting to fetch form element from selector: 'form.wpv-filter-form'
[info] [remote] attempting to fetch form element from selector: 'form.wpv-filter-form'
[info] [remote] attempting to fetch form element from selector: 'form.wpv-filter-form'
[info] [phantom] Step anonymous 5/5: done in 123069ms.
[info] [phantom] Step _step 6/79 https ://domain.com/section/ (HTTP 200)
[info] [phantom] Step _step 6/79: done in 123078ms.

P.s:使用casper.open()是获得二级页面(项目页面)的好方法吗?在获取内容后,我是否需要以某种方式关闭它们?

由于

2 个答案:

答案 0 :(得分:1)

很难给出准确的答案,因为您的问题无法重现。但是,我在你的脚本中注意到了几个问题......

1。避免“筑巢地狱”

CasperJS 围绕步骤进行组织。使用此库,脚本通常如下所示:

casper.start('http://www.website.com/');

casper.then(function () {
  // Step 1
});

casper.then(function () {
  // Step 2
});

casper.then(function () {
  // Step 3
});

casper.run();

then方法不是承诺,但它们具有相同的目标:扁平化代码。因此,当你达到一定程度的嵌套时,你显然做错了。

2。小心evaluate

来自documentation

  

这种方法背后的概念可能是发现CasperJS时最难理解的。提醒一下,将evaluate()方法视为CasperJS环境与您打开的页面之间的门;每当你将一个闭包传递给evaluate()时,你就像进入浏览器控制台一样进入页面并执行代码。

在您的情况下,您在this.evaluate()内使用thenEvaluate()。我确信这不是你想做的......

3。 this并不总是您期望的

如果我们考虑前两个点(嵌套和evaluate),您似乎没有以正确的方式使用this。当您在PhantomJS / CasperJS环境中时,this是您的casper实例。但在evaluate内,您处于页面DOM环境中,这意味着this变为window。如果还不清楚,这是一个示例脚本:

var casper = require('casper').create();

casper.start('http://casperjs.org/');

casper.then(function () {
  // "this" is "casper"
  console.log(this.getCurrentUrl()); // http://casperjs.org/
});

casper.then(function () {
  // "this" is "casper"
  this.echo(this.evaluate(function () {
    // "this" is "window"
    return this.location.href; // http://casperjs.org/
  }));
});

casper.run();

答案 1 :(得分:1)

您的代码中存在许多问题。与不将步骤(then*wait*函数)匹配在一起意味着您将直接调用(casper.fill)与步骤(thenEvaluate)混合在一起。

另一个问题是,this未在页面上下文(casperevaluate内)引用thenEvaluate

这应该有效:

cityNames.forEach(function(cityName){
    casper.then(function(){
        this.fill('form.wpv-filter-form', {   //setting drop-down field value to the city names in order of the items in the array
            'city[]': cityName
        });
    });

    casper.then(function(){
        var regexString = '(\\?)(city)(\\[\\])(=)(' + cityName + ')&';
        var regex = new RegExp(regexString, "igm");
        this.waitForUrl(regex, function(){
            var name = this.getHTML('.kw-details-title');
            link = this.evaluate(getFirstItemLink); // for test, just getting the first item's link

            this.thenOpen(link).then(function(){
                this.echo("New Page is loaded......");
                // Grab the single item contents
            });
        });
    });
});