programing

웹 페이지에서 Ajax 요청이 진행 중인 경우 Java Script를 사용하여 추적하거나 Selenium 웹 드라이버를 통해 XMLHttpRequest 가로채기

starjava 2023. 9. 4. 19:30
반응형

웹 페이지에서 Ajax 요청이 진행 중인 경우 Java Script를 사용하여 추적하거나 Selenium 웹 드라이버를 통해 XMLHttpRequest 가로채기

저는 무한 스크롤이 있는 웹 사이트를 탐색하기 위해 셀레늄 웹 드라이버를 사용하고 있습니다(예를 들어, 다른 웹 사이트도 탐색할 예정입니다!).

문제 설명:

셀레늄 웹 드라이버를 사용하여 콘텐츠 로드가 멈출 때까지 무한 스크롤 페이지를 아래로 스크롤합니다.

의 접근법: 현재 나는 이것을 하고 있습니다.

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));" +
                "}");

그리고 나서 아약스 요청이 이렇게 완료될 때까지 잠시 기다립니다.

2단계: Ajax 요청이 완료될 때까지 명시적으로 대기

스레드.슬립(1000);

그런 다음 페이지가 스크롤 가능한지 확인하기 위해 다른 자바 스크립트를 제공합니다.

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)

위 조건이 참이면 3단계의 조건이 거짓이 될 때까지 1 - 3단계부터 를 반복합니다.

문제:나는 그것을 주고 싶지 않습니다.Thread.sleep(1000);2단계에서는 오히려 자바스크립트를 사용하여 백그라운드 Ajax 요청이 끝났는지 확인한 후 3단계의 조건이 사실인지 더 아래로 스크롤하고 싶습니다.

PS: 저는 페이지 개발자가 아니므로 페이지를 실행하는 코드에 액세스할 수 없습니다. 웹 페이지에 자바 스크립트(1단계와 3단계)를 삽입하면 됩니다.그리고 무한 스크롤 중에 Ajax 요청이 있는 모든 웹 사이트에 대한 일반 로직을 작성해야 합니다.

누군가 여기서 시간을 낼 수 있다면 감사하겠습니다!

편집: 네, 이틀 동안 고생한 후에, 저는 셀레늄 웹 드라이버를 통해 탐색하는 페이지가 이러한 자바스크립트 라이브러리를 가질 수 있다는 것을 알게 되었고 다른 라이브러리에 따라 풀링해야 할 것입니다. 예를 들어, jQuery api를 사용하는 웹 애플리케이션의 경우, 저는 기다릴 수도 있습니다.

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

0을 반환합니다.

마찬가지로 웹 애플리케이션이 프로토타입 자바스크립트 라이브러리를 사용하고 있다면 저는 기다려야 할 것입니다.

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

0을 반환합니다.

문제는 어떻게 하면 대부분의 자바스크립트 라이브러리를 처리할 수 있는 제네릭 코드를 작성할 수 있는가 하는 입니다.

제가 직면한 문제는...

웹 응용 프로그램(자바에서 셀레늄 웹 드라이버 사용)에서 사용 중인 JavaScript 라이브러리를 찾아서 해당 대기 방법을 작성하려면 어떻게 해야 합니까?현재 저는 이것을 사용하고 있습니다.

코드

이렇게 하면 별도의 자바스크립트 라이브러리를 위해 77개의 메소드를 작성해야 하므로 이 시나리오도 더 잘 처리할 수 있는 방법이 필요합니다.

간단히 말해서, 나는 Selenium Web Driver의 java 구현을 통해 브라우저가 JavaScript 라이브러리를 사용하거나 사용하지 않고 호출(Ajax 또는 단순)하고 있는지 확인해야 합니다.

PS: Chorme의 JavaScript Lib 탐지기와 Firefox의 JavaScript Lib 탐지기에는 사용 중인 JavaScript 라이브러리를 탐지하는 추가 기능이 있습니다.

웹 페이지를 열기 전에 무한 스크롤 중에 jQuery API(또는 기타 작업)를 사용하는 Ajax Response가 있는 웹 페이지의 경우.

    //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단계: 지금은 필요 없습니다!

결론:무뚝뚝한 스레드를 줄 필요가 없습니다.sleep(); Selenium WebDriver를 사용하는 동안 계속해서 반복합니다!!

이 접근 방식은 웹 응용 프로그램에서 jQuery api가 사용되는 경우에만 효과적입니다.

편집: @jayati가 제공한 링크에 따라 Javascript를 주입했습니다.

Javascript 1:

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

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

상태 변수의 입니다.ajaxRequestStarted, ajaxRequestComplete자바 코드에서, 사람들은 아약스가 시작되었는지 완료되었는지를 결정할 수 있습니다.

이제 Ajax가 완료될 때까지 기다릴 수 있는 방법이 있습니다. Ajax가 어떤 작업에서 트리거되었는지도 확인할 수 있습니다.

접근법 1:

당신의 접근 방식은 좋으며, 몇 가지 변경만 해도 효과가 있습니다.

이1 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "window.setInterval에서(c >= totalcount)을 부르다window.clearInterval

2:가능한지 , Setp 2: 페지가아직스가확대능인신는하지한롤크이▁set,▁if대,(c >= totalcount) 이 은 그고이조건은 200ms마다시까지 .(c >= totalcount)truetrue를 합니다.

않는 를 참: 1단계가에, Tata-Nano-Reviews-925076578.js 5210라로 부를 수 .c 검사 변수 검사

접근 2:

jQuery API로 이동하여 "ajax"를 입력합니다.Ajax 요청에 사용할 수 있는 일부 콜백 핸들러를 찾을 수 있습니다.

아마도 요청이 전송되기 전과 요청이 적절하게 수신된 후에 변수를 설정합니다.

그리고 그 사이에 더 이상 스크롤할 수 없는 경우를 제외하고는 정기적으로 아래로 스크롤하는 원래 방법을 사용합니다.이때 간격 변수를 지웁니다.

이제 간격 변수가 null인지 정기적으로 확인합니다.Null은 맨 아래에 도달했음을 의미합니다.

우리는 같은 문제를 해결해야 했고 긴 자바스크립트 함수를 사용했습니다.정의되지 않은 라이브러리를 확인하기 위해 체크를 추가하기만 하면 됩니다.

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
}

언급URL : https://stackoverflow.com/questions/11755186/tracking-with-java-script-if-ajax-request-is-going-on-in-a-webpage-or-intercept

반응형