Javascript 同步CasperJS操作期间的异步调用

Javascript 同步CasperJS操作期间的异步调用,javascript,asynchronous,phantomjs,screen-scraping,casperjs,Javascript,Asynchronous,Phantomjs,Screen Scraping,Casperjs,在分配了故障(第一个计时器nodejs和casperjs/phantomjs)之后,它开始工作。我用curl(php)完成了这项工作 这就是我试图实现的目标: 登录 集合所有单位 解析他们的细节 (我的问题)2单元详细信息由ajax调用提供 在下面的函数中,我解析了行,我想添加两个由ajax获取的细节,但我不知道怎么做。(异步) 需要注意的是,最后我想在单元上运行另一个函数,但必须在运行之前获取所有函数 编辑 登录后,页面显示一个表,我得到的表是这样的 身份证 所有者 街头 被跟踪 (通过po

在分配了故障(第一个计时器nodejs和casperjs/phantomjs)之后,它开始工作。我用curl(php)完成了这项工作

这就是我试图实现的目标:

  • 登录
  • 集合所有单位
  • 解析他们的细节
  • (我的问题)2单元详细信息由ajax调用提供
  • 在下面的函数中,我解析了行,我想添加两个由ajax获取的细节,但我不知道怎么做。(异步)

    需要注意的是,最后我想在单元上运行另一个函数,但必须在运行之前获取所有函数

    编辑

    登录后,页面显示一个表,我得到的表是这样的

    • 身份证
    • 所有者
    • 街头
    • 被跟踪 (通过post对链接进行的自动ajax调用)
    • PLACEDABIDON(对链接执行的自动ajax调用) (邮政)
    我试着用casper正常地获取最后2个字段,但有时它得到了值,有时没有(请求有时太慢)

    我想知道的是,如何在不等待每一行(单位)得到值的情况下获得这些字段。(所以每个单元都应该自己获取它们的值,并将它们填入它们的对象中。所以可能需要回调

    或者我可以自己做请求,我只需要ID和cookie来做文章(链接以ID和cookie为参数),获取详细信息并填写,但我不知道如何做,或者第一个解决方案是否工作得更好,或者即使这是可能的

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

    由于PhantomJS(和CasperJS)有两个上下文,因此很容易中断执行流程

    我认为有两种方法可以解决你的问题

    1.自己发送请求 您需要在页面上下文内部(在
    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);
    };
    
    现在,您甚至不需要在
    getUnits()
    中发出Ajax请求,只需收集所有静态信息即可


    不要忘了将失败的等待超时设置得足够大,以便所有Ajax请求都能及时完成。例如,所有Ajax请求的加载时间都比正常时间长3到4倍。您可以使用全局函数来完成此操作。

    仍然不清楚如何调用另一个页面…因为在函数内调用Casper不起作用。您可以这样做吗你是怎么做到的?我觉得你在做一个ajax调用。你现在想要的是完全不同的东西。加载的页面有一些我需要的细节,但2个是从另一个页面(签入网络)通过ajax调用的也许我还需要再等一段时间才能得到它们?那么也许我需要像你说的那样的异步回调,对吗?那么页面本身会执行这些请求?如果是这样,那么你可能需要捕获结果。PhantomJS可以观察请求,但不会公开这些请求的内容。登录后,页面会立即为每个单元显示6个字段但是两个字段有时不显示,因为它们是通过ajax调用获取的(有时速度很慢)。所以我的问题是如何使用casperjs获取它们。在php curl中,我对url进行了同步调用(ajax调用)每个单元都要填写详细信息。为了确保我得到了它们,而不是等待它们显示。但是速度很慢,因为我必须等待到达单元,然后才能继续下一个。所以我想异步完成。但是在所有单元完成后,在继续流的其余部分之前需要完成(我使用逻辑中的数据)
    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);
    };
    
    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);
    };