2014-06-10 15 views
9

Używam PhantomJS, aby zalogować się na stronie i zrobić coś. Witryna wykorzystała protokół OAuth do logowania. Kliknięcie przycisku "Logowanie" powoduje przejście do usługi OAuth. Tam wprowadź swoje dane uwierzytelniające i klikając "Prześlij", nastąpi przekierowanie z powrotem do oryginalnej witryny. Mój skrypt działa dobrze, ale opiera się na limitach czasu, które nie wydają się zbyt mocne.Jak mogę poczekać, aż strona będzie gotowa w PhantomJS?

Jak mogę przepisać ten kod, aby zamiast używać setTimeout, mogę poczekać, aż strona będzie gotowa. Często widzę błędy, że strona nie jest gotowa i dlatego jQuery nie jest inicjowany.

Nie jestem zbyt dobry w JavaScript, więc przykład byłby pomocny. To właśnie zhackowałem razem po tuzinie Googlingów. Oto mój kod:

var page = require('webpage').create(); 
var system = require('system'); 

page.settings.resourceTimeout = 10000; 
page.onResourceTimeout = function(e) { 
    console.log("Timed out loading resource " + e.url); 
}; 

page.open('https://mysite.com/login', function(status) { 
    if (status !== 'success') { 
     console.log('Error opening url'); 
     phantom.exit(1); 
    } else { 
     setTimeout(function() { 
      console.log('Successfully loaded page'); 
      page.evaluate(function() { 
       $("#submit-field").click(); //Clicking the login button 
      }); 

      console.log('Clicked login with OAuth button'); 
      setTimeout(function() { 
       console.log('Addding the credentials'); 
       page.evaluate(function() {     
        document.getElementById("username").value = '[email protected]'; 
        document.getElementById("password").value = '[email protected]'; 
        document.getElementById("Login").click(); 
       }); 
       console.log('Clicked login button'); 

       setTimeout(function() { 
        //Inject some jQuery into the page and invoke that here 
        console.log('Clicked the export button'); 
       }, 15000); 
      }, 15000); 
     }); 
    } 
}); 
+2

Proponuję rozpocząć od oddalenia się od góry zguby. – fmsf

+2

Po pracy z tym przez ostatnie kilka tygodni, wiem teraz, co masz na myśli mówiąc o "górze zagłady". To piekło wywołania zwrotnego. –

Odpowiedz

14

Wydaje się, że jedynym sposobem na to było użycie wywołań zwrotnych z DOM do PhantomJS.

var page = require('webpage').create(); 
var system = require('system'); 

page.onInitialized = function() { 
    page.onCallback = function(data) { 
     console.log('Main page is loaded and ready'); 
     //Do whatever here 
    }; 

    page.evaluate(function() { 
     document.addEventListener('DOMContentLoaded', function() { 
      window.callPhantom(); 
     }, false); 
     console.log("Added listener to wait for page ready"); 
    }); 

}; 

page.open('https://www.google.com', function(status) {}); 
+0

webpage.create() nie jest błędem funkcji, uzyskanie –

+0

@HemantNagarkoti Upewnij się, że strona internetowa jest instalowana jako moduł węzłowy przez npm. 'npm install pagepage --save' – matt

1

Alternatywną metodą byłoby rozszerzenie oprogramowania phantomjs waitfor.js example.

Używam tej mieszanki metodą osobowości. To mój main.js file:

'use strict'; 

var wasSuccessful = phantom.injectJs('./lib/waitFor.js'); 
var page = require('webpage').create(); 

page.open('http://foo.com', function(status) { 
    if (status === 'success') { 
    page.includeJs('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js', function() { 
     waitFor(function() { 
     return page.evaluate(function() { 
      if ('complete' === document.readyState) { 
      return true; 
      } 

      return false; 
     }); 
     }, function() { 
     var fooText = page.evaluate(function() { 
      return $('#foo').text(); 
     }); 

     phantom.exit(); 
     }); 
    }); 
    } else { 
    console.log('error'); 
    phantom.exit(1); 
    } 
}); 

a plik lib/waitFor.js (który jest po prostu skopiować i wkleić funkcji waifFor() z phantomjs waitfor.js example):

function waitFor(testFx, onReady, timeOutMillis) { 
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s 
     start = new Date().getTime(), 
     condition = false, 
     interval = setInterval(function() { 
      if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { 
       // If not time-out yet and condition not yet fulfilled 
       condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 
      } else { 
       if(!condition) { 
        // If condition still not fulfilled (timeout but condition is 'false') 
        console.log("'waitFor()' timeout"); 
        phantom.exit(1); 
       } else { 
        // Condition fulfilled (timeout and/or condition is 'true') 
        // console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 
        typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condi> 
        clearInterval(interval); //< Stop this interval 
       } 
      } 
     }, 250); //< repeat check every 250ms 
} 

Ta metoda jest nie asynchroniczny ale najmniej jestem pewien, że wszystkie zasoby zostały załadowane, zanim spróbuję ich użyć.

Powiązane problemy