在同步CasperJS操作期间进行异步调用

在分配了麻烦之后(第一个定时器nodejs和casperjs / phantomjs)它开始工作。 我用curl(php)做了这个工作。

这是我试图完成的:

  • 登录
  • 获取所有单位
  • 解析他们的细节
  • (我的问题)2个单元细节由ajax调用提供
  • casper.start(url, function() {
          this.evaluate(function() {
              document.querySelector("input[name='username']").value = "username";
              document.querySelector("input[name='password']").value = "passwrd";
              document.querySelector("#login").click();
         });
         console.log("Logged in..");
    });
    
    var processPage = function() {
        console.log("Get all units..");
        var units = this.evaluate(getUnits);
        allUnits.push(units);
    
        if (!this.evaluate(isLastPage)) {
            this.thenClick('.paging li:last-child a').then(function() {
                currentPage++;
                console.log("Stepping to page.. " + currentPage);
                this.waitFor(function() {
                    return currentPage === this.evaluate(getSelectedPage);
                }, processPage, terminate);
            });
        } else{
            require('utils').dump(allUnits);
            casper.then(function() {
                 this.capture('test.png');
            });
            console.log("Total unit count: " + allUnits.length);
        }
    };
    
    
    
     casper.waitForSelector('.units', processPage, terminate);
     casper.run();
    

    在下面的函数中,我解析了行,我想添加2个由ajax获取的细节,但我不知道如何去做。 (异步)

    function getUnits() {
        var rows = document.querySelectorAll('.units');
        var units = [];
    
        for (var i = 0, row; row = rows[i]; i++) {
            var aID = row.querySelector('a').getAttribute('href').split('/');
            unit['id'] = aID[2];
            //add other details for the unit
    
            **//Do a async call to the 2 external links with the ID and add the details to the unit**
    
            units.push(unit);
        } 
    
        return units;
    
    };
    

    重要的是要注意的是,最后我想在单元上运行另一个功能,但是在运行之前必须已经获取所有功能。

    编辑

    登录后,页面显示一张表格,我正在获取该表格

  • ID
  • 所有者
  • BEINGFOLLOWED(自动ajax调用是通过邮件完成的)
  • PLACEDABIDON(对帖子进行链接的自动ajax调用)
  • 我试图通过casper正常获得最后2个字段,但有时它得到的价值,有时它没有(请求有时太慢)

    希望我想知道的是,如何在不等待每行(单位)的情况下获得这些字段,直到获得该值。 (所以每个单位都应该为自己获取价值,并将其填充到自己的对象中。那么可能需要回调吗?

    或者我可以做我的自我请求我只需要ID和cookie来发布帖子(链接以ID和Cookie作为参数)并获取详细信息并填写它,但我不知道该怎么做,或者如果第一个解决方案效果更好,或者即使这是可能的...

    最重要的是,在所有单位都有详细信息之后,它应该继续使用应用程序的逻辑......


    由于PhantomJS(和CasperJS)有两个上下文,所以很容易摆脱执行流程。

    我看到两种方法来解决你的问题。

    1.自己发送请求

    您需要在页面上下文内(在evaluate()内部evaluate()触发请求,并让外部上下文等待结果。 我假设你可以在页面上下文中获得成功的回调。

    你必须把外部请求的结果放在全局的某个地方,以便外部的上下文可以得到它。 例如,像这样修改你的getUnits()函数:

    function getUnits() {
        var rows = document.querySelectorAll('.units');
        var units = [];
        window.__externalRequestResults = [[], []];
    
        for (var i = 0, row; row = rows[i]; i++) {
            var aID = row.querySelector('a').getAttribute('href').split('/');
            unit['id'] = aID[2];
            //add other details for the unit
    
            //Do a async call to the 2 external links with the ID and add the details to the unit
            (function(i){
                var xhr = new XMLHttpRequest();
                xhr.open("GET", someURLwithParameters, true);
                xhr.onreadystatechange = function(){
                    if (xhr.readyState === 4) { // DONE
                        __externalRequestResults[0][i] = xhr.responseText;
                    }
                };
    
                xhr = new XMLHttpRequest();
                xhr.open("GET", someOtherURLwithParameters, true);
                xhr.onreadystatechange = function(){
                    if (xhr.readyState === 4) { // DONE
                        __externalRequestResults[1][i] = xhr.responseText;
                    }
                };
                xhr.send();
            })(i);
    
            units.push(unit);
        } 
    
        return units;
    };
    

    现在您可以检索即时结果,然后等待其他结果:

    var processPage = function() {
        console.log("Get all units..");
        var units = this.evaluate(getUnits);
        var numberOfRows = this.getElementsInfo("table tr").length; // TODO: fix selector
        var externalUnits;
        this.waitFor(function test(){
            externalUnits = this.getGlobal("__externalRequestResults");
            for(var i = 0; i < numberOfRows; i++) {
                if (externalUnits[0][i] == null || externalUnits[1][i] == null) {
                    return false
                }
            }
            return true;
        }, function _then(){
            allUnits.push(units);
            allUnits.push(externalUnits); // TODO: maybe a little differently
    
            if (!this.evaluate(isLastPage)) {
                //... as before
            } else{
                //... as before
            }
        }, terminate);
    };
    

    当两个附加数据列表的数量与表格的行数相同且全部填满时,触发等待期结束。 这将创建一个稀疏数组,并且不能使用Array#push() ,因为不同的Ajax请求可能以不同的顺序发送。

    让浏览器处理请求

    在第二种情况下,您让CasperJS等待所有数据进入。挑战在于编写一个检查函数来执行此操作。

    var processPage = function() {
        console.log("Get all units..");
        var numberOfRows = this.getElementsInfo("table tr").length; // TODO: fix selector
        this.waitFor(function test(){
            var data1, data2;
            for(var i = 1; i <= numberOfRows; i++) {
                data1 = this.fetchText("table tr:nth-child("+i+") td:nth-child(4)") || "";
                data2 = this.fetchText("table tr:nth-child("+i+") td:nth-child(5)") || "";
                if (data1.trim() === "" || data2.trim() === "") {
                    return false
                }
            }
            return true;
        }, function _then(){
            var units = this.evaluate(getUnits);
            allUnits.push(units);
    
            if (!this.evaluate(isLastPage)) {
                //... as before
            } else{
                //... as before
            }
        }, terminate);
    };
    

    现在,您甚至不需要在getUnits()内部发出Ajax请求,并且可以简单地收集所有静态信息。

    不要忘记让失败的等待超时足够大,以便所有Ajax请求及时完成。 例如,对于所有加载的ajax请求,比正常时间大3或4倍。 您可以使用全球casper.options.waitTimeout

    链接地址: http://www.djcxy.com/p/73485.html

    上一篇: Asynchronous call during a synchronous CasperJS operation

    下一篇: CasperJS/PhantomJS Cookie Handling