Подтвердить что ты не робот

Отслеживание с помощью Java Script, если запрос Ajax выполняется на веб-странице или перехват XMLHttpRequest через Selenium Web driver

Я использую Selenium WebDriver для обхода веб-сайта (только, например, я сканирую другие веб-сайты тоже!), который имеет бесконечную прокрутку.

Проблема:

Прокрутите страницу бесконечной прокрутки до тех пор, пока контент не перестанет загружаться с использованием веб-драйвера Selenium.

Мой подход: В настоящее время я делаю это -

Шаг 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

Thread.sleep(1000);

Затем я даю еще один java script, чтобы проверить, прокручивается ли страница

Шаг 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 не станет ложным.

Проблема: Я не хочу давать Thread.sleep(1000); на шаге 2, скорее я бы хотел проверить с помощью Java script, если запрос фона Ajax завершен, а затем прокручивается дальше, если условие на шаге 3 истинно.

PS: Я не разработчик этой страницы, поэтому у меня нет доступа к коду, на котором запущена страница, я могу просто ввести java-скрипты (как на шагах 1 и 3) в Интернете стр. И я должен написать общую логику для любого веб-сайта с запросами Ajax во время бесконечного прокрутки.

Буду благодарен, что кто-то может сэкономить некоторое время здесь!

РЕДАКТИРОВАТЬ: Хорошо, после битвы в течение 2 дней я выяснил, что страницы, которые я просматриваю через Selenium WebDriver, могут иметь любую из этих Библиотеки JavaScript, и мне придется объединять их в соответствии с другой библиотекой, например. В случае веб-приложения, использующего jQuery api, я могу быть ожидая

(Long)((JavascriptExecutor)driver).executeScript("return jQuery.active")

чтобы вернуть нуль.

Аналогично, если веб-приложение использует библиотеку JavaScript Prototype, мне придется ждать

(Long)((JavascriptExecutor)driver).executeScript("return Ajax.activeRequestCount")

чтобы вернуть нуль.

Теперь, проблема заключается в том, как написать общий код, который может обрабатывать большинство доступных библиотек JavaScript?

Проблема, с которой я сталкиваюсь при реализации этого -

1. Как узнать, какая библиотека JavaScript используется в веб-приложении (используя Selenium WebDriver в Java), чтобы затем написать соответствующие методы ожидания? В настоящее время я использую этот

Code

2. Таким образом, мне придется писать целых 77 методов для отдельной библиотеки JavaScript, поэтому мне нужен лучший способ справиться с этим сценарием.

Короче, мне нужно выяснить, делает ли браузер какой-либо вызов (Ajax или простой) с или без какой-либо библиотеки JavaScript через реализацию Java Selenium Web Driver

PS: есть Добавить для Chorme детектор JavaScript Lib и Firefox детектор библиотеки JavaScript, которые обнаруживают Используется библиотека JavaScript.

4b9b3361

Ответ 1

Для веб-страниц с Ajax Response во время бесконечной прокрутки и использования 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 Объединение следующего script (это тот, который устраняет необходимость 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!

Этот подход работает хорошо, только если в веб-приложении используется jQuery api.

EDIT: В соответствии с ссылкой, данной @jayati, я ввел javascript -

Javascript one:

//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 Two:

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();

И проверяя статус статусных vars ajaxRequestStarted, ajaxRequestComplete в java-коде, можно определить, был ли запущен или завершен ajax.

Теперь у меня есть способ дождаться завершения Ajax, я также могу найти, был ли запущен Ajax при некотором действии

Ответ 2

Подход 1:

Ваш подход хорош, только несколько изменений сделали бы трюк:

Шаг 1: улучшите этот шаг, чтобы вызвать функцию toBottom с регулярным интервалом, используя window.setInterval. На (c >= totalcount) вызов window.clearInterval

Setp 2: вместо проверки страницы еще прокручивается, проверьте, есть ли (c >= totalcount). И это условие каждые 200 мс до (c >= totalcount) возвращает true.

FYI: Если шаг 1 не работает во всех браузерах, то, вероятно, вы можете обратиться к строке 5210 Tata-Nano-Reviews-925076578.js и называть это с помощью проверки переменной c.

Подход 2:

Перейдите в jQuery API и введите "ajax". Вы можете найти обработчики обратного вызова, которые могут использоваться для запросов ajax.

Возможно, установите переменную перед отправкой запроса и после того, как она будет получена соответствующим образом.

И в промежутке используйте свой оригинальный метод прокрутки вниз с регулярным интервалом, если только вы больше не можете прокручивать. В этот момент очистите переменную интервала.

Теперь, регулярно проверяйте, является ли эта переменная интервала нулевой или нет. Null означает, что вы достигли дна.

Ответ 3

Нам приходилось решать ту же проблему и управлять длинной функцией Javascript. Просто нужно добавить проверки, чтобы посмотреть, какая библиотека не undefined.

PS Спасибо, что дали мне простой ответ о том, как проверить ход выполнения прототипов!

например. Обрабатывать JQuery и 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
}