如何使用casperjs捕获和处理来自XHR响应的数据?

网页上的数据是动态显示的,检查html中的每一个更改并提取数据似乎是一项非常艰巨的任务,而且还需要我使用非常不可靠的XPath。因此,我希望能够从XHR数据包中提取数据

我希望能够从XHR数据包中提取信息,并生成要发送到服务器的“XHR”数据包。
提取信息部分对我来说更重要,因为通过使用casperjs自动触发html元素,可以轻松处理信息的发送

我附上了我的意思的截图

“响应”选项卡中的文本是我以后需要处理的数据。(已从服务器收到此XHR响应。)

这是不容易做到的,因为资源.received事件处理程序只提供元数据,如url标题或状态,而不提供实际数据。底层的phantomjs事件处理程序的操作方式相同


无状态AJAX请求

如果ajax调用是无状态的,您可以重复该请求

casper.on(“resource.received”,函数(resource){
//在这里以某种方式标识这个请求:如果它包含“.json”
//它还只在阶段“结束”时执行某些操作,否则将执行两次
if(resource.url.indexOf(“.json”)!=-1&resource.stage==“end”){
var data=casper.evaluate(函数(url){
//同步GET请求
返回-utils.sendAJAX(url,“GET”);
},resource.url);
//如果要处理数据,可能需要对JSON.parse(数据)进行解析
}
});
casper.start(url);//你的剧本

您可能希望将事件侦听器添加到资源。请求的。这样,您就不需要为完成呼叫让路了

您也可以在控制流内部这样做(来源:A:CasperJS waitForResource:how to get the resource i've waitForResource):

casper.start(url);
var-res,resData;
casper.waitForResource(函数检查(资源){
res=资源;
返回resource.url.indexOf(“.json”)!=-1;
},函数then(){
resData=casper.evaluate(函数(url){
//同步GET请求
返回-utils.sendAJAX(url,“GET”);
},res.url);
//在此处或稍后的步骤中处理数据
});
casper.run();

有状态AJAX请求

如果它不是无状态的,则需要替换XMLHttpRequest的实现。您需要注入自己的onreadystatechange处理程序实现,在页面窗口对象中收集信息,然后在另一个evaluate调用中收集信息

您可能希望查看sinon.js中的XHR伪造程序,或者使用XMLHttpRequest的以下完整代理(我根据“如何创建XMLHttpRequest包装器/代理?”中的方法3对其建模):

函数替换xhr(){
(功能(窗口,调试){
函数args(a){
var s=“”;
对于(变量i=0;i<a.length;i++){
s+=“\t\n[“+i+”]=>“+a[i];
}
返回s;
}
var_XMLHttpRequest=window.XMLHttpRequest;
window.XMLHttpRequest=函数(){
this.xhr=new_XMLHttpRequest();
}
//代理所有方法/属性
var方法=[
“开放”,
“中止”,
“setRequestHeader”,
“发送”,
“addEventListener”,
“removeEventListener”,
“getResponseHeader”,
“getAllResponseHeaders”,
“调度事件”,
“重写emimetype”
];
方法。forEach(函数(方法){
window.XMLHttpRequest.prototype[方法]=函数(){
if(debug)console.log(“ARGUMENTS”,方法,args(ARGUMENTS));
如果(方法==“打开”){
这个。_url=arguments[1];
}
返回this.xhr[method].apply(this.xhr,参数);
}
});
//代理更改事件处理程序
Object.defineProperty(window.XMLHttpRequest.prototype,“onreadystatechange”{
get:function(){
//这可能永远不会被调用
返回this.xhr.onreadystatechange;
},
设置:函数(onreadystatechange){
var=this.xhr;
var realThis=这个;
that.onreadystatechange=函数(){
//请求已完全加载
如果(that.readyState==4){
如果(调试)console.log(“收到的响应:”,typeof that.responseText==“string”?that.responseText.length:“无”);
//存在基于url的响应和筛选器执行
如果(that.responseText&realThis.\u url.indexOf(“任意”)!=-1){
window.myAwesomeResponse=that.responseText;
}
}
onreadystatechange.call(that);
};
}
});
var其他标量=[
“onabort”,
“onerror”,
“加载”,
“onloadstart”,
“onloadend”,
“关于进展”,
“readyState”,
“responseText”,
“responseType”,
“responseXML”,
“地位”,
“状态文本”,
“上传”,
“凭证件”,
“完成”,
“未发送”,
“收到的标题”,
“加载”,
“打开”
];
forEach(函数(标量){
Object.defineProperty(window.XMLHttpRequest.prototype,标量{
get:function(){
返回这个.xhr[scalar];
},
设置:功能(obj){
this.xhr[scalar]=obj;
}
});
});
})(假窗口);
}

如果希望从一开始就捕获AJAX调用,则需要将其添加到第一个事件处理程序中

casper.on(“page.initialized”),函数(资源){
这个。评估(替换XHR);
});

或者在需要时评估(replaceXHR)

控制流如下所示:

函数replaceXHR(){/*自上*/}
start(yourUrl,function()){
这个。评估(替换XHR);
});
函数getAwesomeResponse(){
返回此值。evaluate(函数(){
return window.myAwesomeResponse;
});
}
//如果window.myAwesomeResponse的计算结果为true,则停止等待
waitFor(getAwesomeResponse,函数then()){
var data=JSON.parse(getAwesomeResponse());
//处理数据
});
casper.run();

如上所述,我为XMLHttpRequest创建了一个代理,这样每次在页面上使用它时,我都可以使用它做一些事情。刮取的页面使用xhr.onreadystatechange回调来接收数据。代理是通过定义一个特定的setter函数来完成的,该函数将接收到的数据写入页面上下文中的window.myAwesomeResponse。您需要做的唯一一件事就是检索此文本


JSONP请求

如果您知道前缀(使用加载的JSON调用的函数,例如insert({“data”:[“Some”,“JSON”,“here”],“id:“asdasda”)),那么为JSONP编写代理就更容易了。您可以在页面上下文中覆盖insert

  1. 加载页面后

    casper.start(url).then(function(){
    这个。evaluate(函数(){
    var oldsert=insert;
    insert=函数(json){
    window.myAwesomeResponse=json;
    应用(窗口、参数);
    };
    });
    }).waitFor(getAwesomeResponse,函数then()){
    var data=JSON.parse(getAwesomeResponse());
    //处理数据
    }).run();
    
  2. 或者在收到请求之前(如果函数是在调用请求之前注册的)

    casper.on(“resource.requested”,函数(resource){
    //过滤正确的呼叫
    if(resource.url.indexOf(“.jsonp”)!=-1){
    这个。evaluate(函数(){
    var oldsert=insert;
    insert=函数(json){
    window.myAwesomeResponse=json;
    应用(窗口、参数);
    };
    });
    }
    }).run();
    casper.start(url).waitFor(getAwesomeResponse,函数then()){
    var data=JSON.parse(getAwesomeResponse());
    //处理数据
    }).run();
    

发表评论