使用Java脚本跟踪网页中是否有Ajax请求,或者通过Selenium Web驱动程序拦截XMLHttpRequest
Tracking with Java Script if Ajax request is going on in a webpage or Intercept XMLHttpRequest through Selenium Web driver
我正在使用Selenium WebDriver对具有无限滚动的网站进行爬网(仅举个例子,我也将对其他网站进行爬网!)。
问题说明:
向下滚动无限滚动页面,直到使用Selenium web驱动程序停止加载内容。
我的方法:目前我正在做这个-
步骤1:滚动至页面底部
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("javascript:window.onload=toBottom();"+
"function toBottom(){" +
"window.scrollTo(0,Math.max(document.documentElement.scrollHeight," +
"document.body.scrollHeight,document.documentElement.clientHeight));" +
"}");
然后我等待一段时间,让Ajax请求像这样完成-
步骤2:明确等待Ajax请求结束
线程睡眠(1000);
然后我给出另一个java脚本来检查页面是否是可滚动的
步骤3:检查页面是否可滚动
//Alternative to document.height is to be used which is document.body.clientHeight
//refer to https://developer.mozilla.org/en-US/docs/DOM/document.height
if((Long)js.executeScript("return " +
"(document.body.clientHeight-(window.pageYOffset + window.innerHeight))")>0)
如果上述条件为真,则我重复步骤1-3,直到步骤3中的条件为假。
问题:我不想在步骤2中给出Thread.sleep(1000);
,而是希望使用JavaScript检查后台Ajax请求是否结束,然后如果步骤3中的条件为true,则进一步向下滚动。
PS:我不是该页面的开发人员,因此我无法访问运行该页面的代码,我只能在网页中注入java脚本(如步骤1和3所示)。而且,我必须为任何在无限滚动期间有Ajax请求的网站编写一个通用逻辑。
如果有人能抽出时间来,我会很感激的!
编辑:好的,经过2天的努力,我发现我在Selenium WebDriver中爬行的页面可以有这些JavaScript库中的任何一个,我必须根据不同的库进行池化,例如,如果web应用程序使用jQuery api,我可能正在等待
(Long)((JavascriptExecutor)driver).executeScript("return jQuery.active")
以返回零。
同样,如果web应用程序正在使用Prototype JavaScript库,我将不得不等待
(Long)((JavascriptExecutor)driver).executeScript("return Ajax.activeRequestCount")
以返回零。
现在,问题是如何编写能够处理大多数可用JavaScript库的通用代码
我在实现这个过程中面临的问题-
1。如何查找Web应用程序中正在使用的JavaScript库(使用Java中的Selenium WebDriver),以便编写相应的等待方法?目前,我正在使用这个
代码
2。这样,我将不得不为单独的JavaScript库编写多达77个方法,因此,我也需要一种更好的方法来处理这种情况。
简而言之,我需要通过SeleniumWebDriver的java实现来判断浏览器是否在有或没有任何JavaScript库的情况下进行任何调用(Ajax或simple)
附言:Chorme的JavaScriptLib检测器和Firefox的JavaScriptLibrary检测器都有插件,可以检测正在使用的JavaScript库。
对于在无限滚动期间使用Ajax响应并使用jQuery API(或其他操作)的网页,在开始打开网页之前。
//Inject the pooling status variable
js.executeScript("window.status = 'fail';");
//Attach the Ajax call back method
js.executeScript( "$(document).ajaxComplete(function() {" +
"status = 'success';});");
步骤1:将保持与原始问题中相同
步骤2汇集以下脚本(这是一个消除Thread.Sleep()
需求并使逻辑更动态的脚本)
String aStatus = (String)js.executeScript("return status;");
if(aStatus!=null && aStatus.equalsIgnoreCase("success")){
js.executeScript("status = 'fail';");
break poolingLoop;
}
第3步:现在不需要了!
结论:无需给出钝Thread.sleep();一次又一次地使用Selenium WebDriver!!
只有当web应用程序中使用jQueryapi时,这种方法才有效
编辑:根据@jayati给出的链接,我注入了javascript-
Javascript一:
//XMLHttpRequest instrumentation/wrapping
var startTracing = function (onnew) {
var OldXHR = window.XMLHttpRequest;
// create a wrapper object that has the same interfaces as a regular XMLHttpRequest object
// see http://www.xulplanet.com/references/objref/XMLHttpRequest.html for reference on XHR object
var NewXHR = function() {
var self = this;
var actualXHR = new OldXHR();
// private callbacks (for UI):
// onopen, onsend, onsetrequestheader, onupdate, ...
this.requestHeaders = "";
this.requestBody = "";
// emulate methods from regular XMLHttpRequest object
this.open = function(a, b, c, d, e) {
self.openMethod = a.toUpperCase();
self.openURL = b;
ajaxRequestStarted = 'open';
if (self.onopen != null && typeof(self.onopen) == "function") {
self.onopen(a,b,c,d,e); }
return actualXHR.open(a,b,c,d,e);
}
this.send = function(a) {
ajaxRequestStarted = 'send';
if (self.onsend != null && typeof(this.onsend) == "function") {
self.onsend(a); }
self.requestBody += a;
return actualXHR.send(a);
}
this.setRequestHeader = function(a, b) {
if (self.onsetrequestheader != null && typeof(self.onsetrequestheader) == "function") { self.onsetrequestheader(a, b); }
self.requestHeaders += a + ":" + b + "'r'n";
return actualXHR.setRequestHeader(a, b);
}
this.getRequestHeader = function() {
return actualXHR.getRequestHeader();
}
this.getResponseHeader = function(a) { return actualXHR.getResponseHeader(a); }
this.getAllResponseHeaders = function() { return actualXHR.getAllResponseHeaders(); }
this.abort = function() { return actualXHR.abort(); }
this.addEventListener = function(a, b, c) { return actualXHR.addEventListener(a, b, c); }
this.dispatchEvent = function(e) { return actualXHR.dispatchEvent(e); }
this.openRequest = function(a, b, c, d, e) { return actualXHR.openRequest(a, b, c, d, e); }
this.overrideMimeType = function(e) { return actualXHR.overrideMimeType(e); }
this.removeEventListener = function(a, b, c) { return actualXHR.removeEventListener(a, b, c); }
// copy the values from actualXHR back onto self
function copyState() {
// copy properties back from the actual XHR to the wrapper
try {
self.readyState = actualXHR.readyState;
} catch (e) {}
try {
self.status = actualXHR.status;
} catch (e) {}
try {
self.responseText = actualXHR.responseText;
} catch (e) {}
try {
self.statusText = actualXHR.statusText;
} catch (e) {}
try {
self.responseXML = actualXHR.responseXML;
} catch (e) {}
}
// emulate callbacks from regular XMLHttpRequest object
actualXHR.onreadystatechange = function() {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
// onreadystatechange callback
if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") { return self.onreadystatechange(); }
}
actualXHR.onerror = function(e) {
ajaxRequestComplete = 'err';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onerror != null && typeof(self.onerror) == "function") {
return self.onerror(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onload = function(e) {
ajaxRequestComplete = 'loaded';
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onload != null && typeof(self.onload) == "function") {
return self.onload(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
actualXHR.onprogress = function(e) {
copyState();
try {
if (self.onupdate != null && typeof(self.onupdate) == "function") { self.onupdate(); }
} catch (e) {}
if (self.onprogress != null && typeof(self.onprogress) == "function") {
return self.onprogress(e);
} else if (self.onreadystatechange != null && typeof(self.onreadystatechange) == "function") {
return self.onreadystatechange();
}
}
if (onnew && typeof(onnew) == "function") { onnew(this); }
}
window.XMLHttpRequest = NewXHR;
}
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
startTracing();
或者Javascript二:
var startTracing = function (onnew) {
window.ajaxRequestComplete = 'no';//Make as a global javascript variable
window.ajaxRequestStarted = 'no';
XMLHttpRequest.prototype.uniqueID = function() {
if (!this.uniqueIDMemo) {
this.uniqueIDMemo = Math.floor(Math.random() * 1000);
}
return this.uniqueIDMemo;
}
XMLHttpRequest.prototype.oldOpen = XMLHttpRequest.prototype.open;
var newOpen = function(method, url, async, user, password) {
ajaxRequestStarted = 'open';
/*alert(ajaxRequestStarted);*/
this.oldOpen(method, url, async, user, password);
}
XMLHttpRequest.prototype.open = newOpen;
XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;
var newSend = function(a) {
var xhr = this;
var onload = function() {
ajaxRequestComplete = 'loaded';
/*alert(ajaxRequestComplete);*/
};
var onerror = function( ) {
ajaxRequestComplete = 'Err';
/*alert(ajaxRequestComplete);*/
};
xhr.addEventListener("load", onload, false);
xhr.addEventListener("error", onerror, false);
xhr.oldSend(a);
}
XMLHttpRequest.prototype.send = newSend;
}
startTracing();
通过检查java代码中状态变量ajaxRequestStarted, ajaxRequestComplete
的状态,可以确定ajax是启动还是完成。
现在我有一种方法可以等到Ajax完成,我还可以找到Ajax是否是在某个操作上触发的
方法1:
你的方法很好,只要做一些改变就可以了:
步骤1:改进此步骤,使用window.setInterval
定期调用toBottom函数。在(c >= totalcount)
呼叫window.clearInterval
设置2:与其检查页面是否可滚动,不如检查(c >= totalcount)
。并且该条件每200ms一次,直到(c >= totalcount)
返回真。
仅供参考:如果步骤1在所有浏览器中都不起作用,那么你可能可以参考Tata-Nano-Reviews-925076578.js的第5210行,并用c
变量检查来调用它。
方法2:
转到jQuery API并键入"ajax"。您可以找到一些可以用于ajax请求的回调处理程序。
可能在发送请求之前和适当地接收请求之后设置一个变量。
在这两者之间,除非你不能再滚动,否则使用你原来的方法,每隔一段时间滚动到底。此时,清除间隔变量。
现在,定期检查该间隔变量是否为null。空表示您已到达底部。
我们不得不解决同样的问题,并使用长Javascript函数进行管理。只需添加检查即可查看哪个库未定义。
PS谢谢你给我一个简单的答案,告诉我如何检查正在进行的原型请求!
例如。处理JQuery和XHR/原型
var jsExecutor = /*Get your WebDriverInstance*/ as IJavaScriptExecutor;
while(/*your required timeout here*/)
{
var ajaxComplete =
jsExecutor.ExecuteScript("return ((typeof Ajax === 'undefined') ||
Ajax.activeRequestCount == 0) && ((typeof jQuery === 'undefined') || $.active == 0)");
if (ajaxIsComplete)
return
}
- Javascript:selenium Web驱动程序isDisplayed()不工作
- WebDriverException:tinyMCE未在selenium Web driver java中定义
- python-selenium-点击上升链接
- Selenium Web驱动程序和javascript
- Selenium WebDriver and JavaScript change
- 如何删除除冒号、数字和'上午'或者'下午'
- 如何“;过滤器”;或者以其他方式重构该数据
- 哪个布尔运算更快<或者<=
- Selenium驱动程序不反映单击()后的页面更改
- 在编译阶段后创建新的DOM树,或者继续使用原始修改的DOM
- 或者在表单上选择默认选项文本(选择1)
- Selenium无法在浏览器DOM中定位元素
- 试图修改此javascript代码以减小弹出窗口的大小,或者在用户单击框外时关闭
- 无法使用Selenium创建本地windows目录结构
- Xpath对Selenium Web驱动程序无效”;Xpath未找到”;
- 运行Selenium Webdriver Test时,不会出现警报
- JQuery是否有一个“;移动“;作用或者有没有一种更紧凑的方法来做到这一点
- Selenium RemoteWebDriver中的批处理/原子操作
- 咖啡'@'或者这在函数和类中
- 使用Java脚本跟踪网页中是否有Ajax请求,或者通过Selenium Web驱动程序拦截XMLHttpRequest