【问题标题】:CasperJS - Access page's content while trying to fill drop-down menu through a loopCasperJS - 在尝试通过循环填充下拉菜单时访问页面的内容
【发布时间】:2017-05-25 09:24:07
【问题描述】:

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

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

  • 然后选择每个城市(带有casper.fill()),这会导致加载新 页面上的内容和 URL 发生变化,(成功在使用单个城市名称进行测试时,失败在城市名称列表中循环)

  • 通过新加载项的链接(新页面)更进一步,

  • 最后,抓取每一页的内容

我试图做一个循环来遍历城市列表并在每个循环中完成所有工作。但问题是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() 是否是到达二级页面(项目页面)的好方法?获取内容后是否需要以某种方式关闭它们?

谢谢

【问题讨论】:

    标签: javascript web-scraping casperjs


    【解决方案1】:

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

    另一个问题是this 不引用页面上下文内部的casper(在evaluatethenEvaluate 内部)。

    这应该可行:

    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
                });
            });
        });
    });
    

    【讨论】:

    • 感谢亲爱的 Artjom,我必须将您的代码包装在 casper.then() 中才能执行。另外,显然我应该将cityName 参数添加到包括casper.fills() 的方法函数中。否则,它会返回一个对象来填写表单。我无法在 url 更改后使用casper. WaitForUrl () 继续循环,并且遇到 invalid url 错误问题,因此我禁用了正则表达式方法并使用了your solution here instead。所以这是工作代码:paste.ubuntu.com/24671718
    • 但是我还是遇到了一个大问题,在第一个循环中打开第一个链接后 PhantomJS 崩溃了。 我需要打开链接,获取它们的内容并关闭它们(对于为了性能)。我在这里看到了您的答案:stackoverflow.com/a/32478245/190929 但无法解决我的问题。
    • 您会像我在这里展示的那样编辑您的答案吗:(paste.ubuntu.com/24671718)所以我将其标记为已接受的答案?另外,如果您同意,我会发布崩溃问题以及有关打开和关闭页面的优化方法的问题;并在此处提供链接。
    • 对不起,我的第一个版本的答案有错误。无论您使用waitForUrl 还是waitForUrlChange 并没有真正的区别。我不会进一步更改我的答案,但您可以发布自己的答案并接受它。
    【解决方案2】:

    很难给你一个准确的答案,因为你的问题是不可能重现的。但是,我注意到您的脚本中有几个问题...

    1。避免“筑巢地狱”

    CasperJS 是围绕 steps 组织的。使用此库,脚本通常如下所示:

    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() 时,您都在进入页面并执行代码,就像使用浏览器控制台一样。

    在您的情况下,您在thenEvaluate() 中使用this.evaluate()。我敢肯定这不是你想要做的......

    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();
    

    【讨论】:

    • 谢谢亲爱的巴达卡达布拉; this 在不同概念中的澄清非常有用。我已经根据您的建议重建了我的代码,但仍然没有机会。 Here 是重构代码。确切的问题在代码中暴露为 cmets:paste.ubuntu.com/24659583
    猜你喜欢
    • 2018-10-30
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多