Suivi avec le Script Java si la requête Ajax est en cours dans une page Web ou intercepter XMLHttpRequest par le biais du pilote web Selenium
j'utilise Selenium WebDriver pour l'analyse d'un site web(seulement par exemple, je vais ramper d'autres sites Web aussi!) qui possède une infinité de défilement.
énoncé du problème:
Faites défiler vers le bas la page de défilement infini jusqu'à ce que le contenu cesse le chargement en utilisant le pilote de web de sélénium.
Mon Approche: Actuellement je fais cela -
Étape 1: Faites défiler Jusqu'à la page bas
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));" +
"}");
puis j'attends un certain temps pour laisser la requête Ajax complète comme ceci-
Étape 2: Explicitement attendre à une requête Ajax pour être sur
Thread.sleep (1000);
puis je donne un autre script java pour vérifier si la page est scrollable
Etape 3: Vérifiez si la page est scrollable
//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)
si la condition ci-dessus est vraie alors je répète l'étape 1-3, jusqu'à la condition dans L'Étape 3 est fausse.
Le Problème:
Je ne veux pas donner l' Thread.sleep(1000);
à l'étape 2, j'aimerais plutôt vérifier en utilisant le Script Java si la requête Ajax en arrière-plan est terminée et ensuite faire défiler vers le bas si la condition à l'Étape 3 est vraie .
PS: Je ne suis pas le développeur de la page donc je n'ai pas accès au code qui exécute la page, je peux juste injecter des scripts java (comme dans les étapes 1 et 3) dans le web page. Et, je dois écrire une logique générique pour tout site Web avec des requêtes Ajax pendant infinite scroll.
je serai reconnaissant à quelqu'un qui pourrait passer du temps ici!
EDIT : Ok, après avoir lutté pendant 2 jours, j'ai compris que les pages que je suis en train de parcourir le WebDriver du sélénium peuvent avoir n'importe lequel de ces bibliothèques JavaScript et j'ai de la piscine selon les différents Bibliothèque, par exemple, Dans le cas du web application à l'aide de jQuery api, j'ai peut-être en attente d'
(Long)((JavascriptExecutor)driver).executeScript("return jQuery.active")
pour retourner un zéro.
de même si l'application web utilise le Prototype bibliothèque JavaScript je vais devoir attendre pour
(Long)((JavascriptExecutor)driver).executeScript("return Ajax.activeRequestCount")
pour retourner un zéro.
,le problème est de savoir comment écrire un code générique qui pourrait traiter la plupart des bibliothèques JavaScript disponibles?
Problème, Je je fais face à la mise en œuvre de ce-
1. Comment puis-je trouver quelle bibliothèque JavaScript est utilisée dans L'Application Web(en utilisant Selenium WebDriver en Java), de sorte que je puisse ensuite écrire les méthodes d'attente correspondantes? Actuellement, je l'utilise
2. De cette façon, je dois écrire autant que 77 méthodes pour séparer bibliothèque JavaScript donc, j'ai besoin d'une meilleure façon de gérer ce scénario.
en bref, je dois savoir si le navigateur fait un appel (Ajax ou simple) avec ou sans bibliothèque JavaScript par le biais de L'implémentation java de Selenium Web Driver
PS: il y a des addons pour JavaScript Lib detector Firefox Bibliothèque JavaScript détecteur qui détectent la bibliothèque JavaScript utilisé.
3 réponses
pour les pages Web avec réponse Ajax pendant le scroll infini et en utilisant L'API jQuery (ou d'autres actions), avant de commencer à ouvrir la page web.
//Inject the pooling status variable
js.executeScript("window.status = 'fail';");
//Attach the Ajax call back method
js.executeScript( "$(document).ajaxComplete(function() {" +
"status = 'success';});");
Étape 1: restera le même que dans la question originale
Etape 2 mise en commun du script suivant (c'est celui qui supprime le besoin de Thread.Sleep()
et rend la logique plus dynamique)
String aStatus = (String)js.executeScript("return status;");
if(aStatus!=null && aStatus.equalsIgnoreCase("success")){
js.executeScript("status = 'fail';");
break poolingLoop;
}
Etape 3: Pas besoin maintenant!
Conclusion: Pas besoin de donner blunt Fil.sleep(); encore et encore tout en utilisant Selenium WebDriver!!
cette approche ne fonctionne bien que si l'api jQuery est utilisée dans l'application web.
EDIT: Comme par le lien donné par @jayati j'ai injecté le 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();
Ou Javascript Deux:
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();
et de vérifier l'état de l'état vars ajaxRequestStarted, ajaxRequestComplete
dans le code java, on peut déterminer si l'ajax a été commencé ou terminé.
maintenant j'ai un moyen d'attendre jusqu'à ce qu'un Ajax soit complet, je peux aussi trouver si L'Ajax a été déclenché sur une action
approche 1:
Votre démarche est la bonne, juste quelques changements pourraient faire l'affaire:
Etape 1: Améliorer cette étape pour appeler la fonction toBottom à intervalle régulier en utilisant window.setInterval
. (c >= totalcount)
appel window.clearInterval
Setp 2: au lieu de vérifier que la page est encore scrollable, vérifiez si (c >= totalcount)
. Et cette condition tous les 200ms jusqu'à (c >= totalcount)
renvoie la valeur true.
FYI: si L'Étape 1 ne fonctionne pas dans tous les navigateurs, alors probablement, vous pouvez reportez-vous à la ligne 5210 de Tata-Nano-Reviews-925076578.js et appeler cela avec c
vérification des variables.
approche 2:
jQuery API et tapez "ajax". Vous pouvez trouver quelques gestionnaires de callback qui pourraient être utilisés pour les requêtes ajax.
probablement, définissez une variable avant que la requête ne soit envoyée et après qu'elle ait été reçue de manière appropriée.
et entre les deux Utilisez votre méthode originale de défilement vers le bas à l'ordinaire intervalle, sauf si vous ne pouvez plus faire défiler. À ce point, effacer la variable intervalle.
maintenant, Vérifiez régulièrement si cette variable d'intervalle est nulle ou non. Nul signifie que vous avez atteint le fond.
nous avons dû résoudre le même problème, et géré en utilisant une longue fonction Javascript. Juste besoin d'ajouter vérifie que la bibliothèque n'est pas indéfini.
PS merci de me donner une réponse facile pour la façon de vérifier les demandes de prototypes en cours!
par exemple. Handle JQuery et XHR / Prototype
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
}