Tracking with JavaScript if Ajax request is going on in a webpage or Intercept XMLHttpRequest through Selenium Web driver

后端 未结 3 399
灰色年华
灰色年华 2021-02-01 20:32

I am using Selenium WebDriver for crawling a web site(only for example, I will be crawling other web sites too!) which has infinite scroll.

Problem statement:

相关标签:
3条回答
  • 2021-02-01 21:14

    We had to solve the same problem, and managed using a long Javascript function. Just need to add checks to see which library is not undefined.

    PS Thanks for giving me an easy answer for how to check for in progress Prototype requests!

    eg. Handle JQuery and 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
    }
    
    0 讨论(0)
  • 2021-02-01 21:15

    For web pages with Ajax Response during the infinite scroll and using jQuery API(or other actions), before starting to opening the web page.

        //Inject the pooling status variable
        js.executeScript("window.status = 'fail';");
    
        //Attach the Ajax call back method
        js.executeScript( "$(document).ajaxComplete(function() {" +
        "status = 'success';});");
    

    Step 1: will remain the same as in the original question

    Step 2 Pooling the following script(This is the one which removes the need of Thread.Sleep() and makes the logic more dynamic)

    String aStatus = (String)js.executeScript("return status;");
    
                            if(aStatus!=null && aStatus.equalsIgnoreCase("success")){
                                js.executeScript("status = 'fail';");
                                break poolingLoop;
                            }
    

    Step 3: No need now!

    Conclusion: No need to give blunt Thread.sleep(); again and again while using Selenium WebDriver!!

    This approach works good only if there's jQuery api being used in the web application.

    EDIT: As per the the link given by @jayati i injected the 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();
    

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

    And checking the status of the status vars ajaxRequestStarted, ajaxRequestComplete in the java code, one can determine if the ajax was started or completed.

    Now I have a way to wait till an Ajax is complete, I can also find if the Ajax was triggered on some action

    0 讨论(0)
  • 2021-02-01 21:22

    Approach 1:

    Your approach is good, just a few changes would do the trick:

    Step 1: Improve this step to call the toBottom function at regular interval using window.setInterval. At (c >= totalcount) call window.clearInterval

    Setp 2: Instead of checking the page is yet scrollable, check if (c >= totalcount). And this condition every 200ms until (c >= totalcount) returns true.

    FYI: If the Step 1 doesn't work in all the browsers then probably, you can refer to line 5210 of Tata-Nano-Reviews-925076578.js and call this with cvariable checking.

    Approach 2:

    Go to jQuery API and type "ajax". You can find some callback handlers which could be used for ajax requests.

    Probably, set a variable before the request is been sent and after it is been received appropriately.

    And in between use your original method of scrolling to bottom at regular interval, unless you can no more scroll. At this point clear the interval variable.

    Now, regularly check if that interval variable is null or not. Null would mean that you have reached the bottom.

    0 讨论(0)
提交回复
热议问题