web-dev-qa-db-fra.com

Comment attendre qu'un événement click () se charge dans phantomjs avant de continuer?

Phantomjs a ces deux callbacks vraiment utiles onLoadStarted et onLoadFinished qui vous permettent de suspendre l'exécution pendant le chargement de la page. Mais j'ai cherché et je ne trouve pas d'équivalent si vous click() un bouton ou un lien hypertexte. Un chargement de page similaire se produit mais onLoadStarted n'est pas appelé pour cet événement, car il n'y a pas de page.open() explicite. J'essaie de trouver un moyen propre de suspendre l'exécution pendant le chargement.

L'une des solutions est évidemment celle de setTimeout imbriquée, mais j'aimerais éviter ce scénario car il est hacky et repose sur des essais et des erreurs au lieu de quelque chose de plus fiable et robuste, comme tester contre quelque chose ou attendre un événement.

Existe-t-il un rappel spécifique pour ce type de chargement de page que j'ai manquée? Ou peut-être y a-t-il une sorte de modèle de code générique pouvant traiter ce genre de chose?

MODIFIER:

Je n'ai toujours pas compris comment le mettre en pause. Voici le code qui n'appelle pas la fonction onLoadStarted() lorsque j'appelle la commande click():

var loadInProgress = false;

page.onLoadStarted = function() {
  loadInProgress = true;
  console.log("load started");
};

page.onLoadFinished = function() {
  loadInProgress = false;
  console.log("load finished");
};

page.open(loginPage.url, function (status) {
    if (status !== 'success') {
        console.log('Unable to access network');
        fs.write(filePath + errorState, 1, 'w');
        phantom.exit();
    } else {
        page.evaluate(function (loginPage, credentials) {
            console.log('inside loginPage evaluate function...\n')
            document.querySelector('input[id=' + loginPage.userId + ']').value = credentials.username;
            document.querySelector('input[id=' + loginPage.passId + ']').value = credentials.password;      
            document.querySelector('input[id=' + loginPage.submitId + ']').click();
            //var aTags = document.getElementsByTagName('a')
            //aTags[1].click();
        }, loginPage, credentials);

        page.render(renderPath + 'postLogin.png');
        console.log('rendered post-login');

J'ai vérifié deux fois que l'identifiant est correct. La page.render() indiquera que les informations sont soumises, mais uniquement si je les mets dans un setTimeout (), sinon, elles sont rendues immédiatement et je ne vois que les informations d'identification entrées avant la redirection de page. Peut-être que je manque quelque chose d'autre?

17
Jpaji Rajnish

Je pense que les fonctions onLoadStarted et onLoadFinished sont tout ce dont vous avez besoin. Prenons par exemple le script suivant:

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

page.onResourceReceived = function(response) {
    if (response.stage !== "end") return;
    console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + response.url);
};
page.onResourceRequested = function(requestData, networkRequest) {
    console.log('Request (#' + requestData.id + '): ' + requestData.url);
};
page.onUrlChanged = function(targetUrl) {
    console.log('New URL: ' + targetUrl);
};
page.onLoadFinished = function(status) {
    console.log('Load Finished: ' + status);
};
page.onLoadStarted = function() {
    console.log('Load Started');
};
page.onNavigationRequested = function(url, type, willNavigate, main) {
    console.log('Trying to navigate to: ' + url);
};

page.open("http://example.com", function(status){
    page.evaluate(function(){
        // click
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        document.querySelector("a").dispatchEvent(e);
    });
    setTimeout(function(){
        phantom.exit();
    }, 10000);
});

Il imprime 

 Tentative de navigation vers: http://example.com/
Request (# 1): http://example.com/
Load Started
New URL: http: // example. com /
 Réponse (# 1, étape "fin"): http://example.com/
Load Terminé: success 
 Tentative de navigation vers: http://www.iana.org/domains /example
Request (# 2): http://www.iana.org/domains/example
Load Started 
 Tentative de navigation vers: http://www.iana.org/domains/reserved 
 Requête (n ° 3): http://www.iana.org/domains/reserved
Response (n ° 2, étape "fin"): http://www.iana.org/domains/exemple
Nouvelle URL: http://www.iana.org/domains/reserved
Request (# 4): http://www.iana.org/_css/2013.1/screen.css
Request (# 5): http://www.iana.org/_js/2013.1/jquery.js
Request (# 6): http://www.iana.org/_js/2013.1/iana.js
Response (# 3, étape "fin"): http://www.iana.org/domains/reserved
Response (# 6, étape "fin"): http://www.iana.org/_js/2013.1 /iana.js
Response (# 4, étape "fin"): http://www.iana.org/_css/2013.1/screen.css
Response (# 5, étape "fin"): http : // www .iana.org/_js/2013.1/jquery.js 
 Requête (n ° 7): http://www.iana.org/_img/2013.1/iana-logo-header.svg
Demande (n ° 8) : http://www.iana.org/_img/2013.1/icann-logo.svg
Response (# 8, étape "fin"): http://www.iana.org/_img/2013.1/icann- logo.svg 
 Réponse (n ° 7, étape "fin"): http://www.iana.org/_img/2013.1/iana-logo-header.svg
Request (n ° 9): http://www.iana.org/_css/2013.1/print.css
Response (# 9, étape "fin"): http://www.iana.org/_css/2013.1/print.css
Charge terminée : Succès

Cela montre que cliquer sur un lien émet deux fois l'événement LoadStarted et deux fois l'événement NavigationRequested, car il existe une redirection. L'astuce consiste à ajouter les gestionnaires d'événements avant d'effectuer l'action:

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

page.open("http://example.com", function(status){
    page.onLoadFinished = function(status) {
        console.log('Load Finished: ' + status);
        page.render("test37_next_page.png");
        phantom.exit();
    };
    page.onLoadStarted = function() {
        console.log('Load Started');
    };

    page.evaluate(function(){
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        document.querySelector("a").dispatchEvent(e);
    });
});

Si vous devez faire ces choses, il est peut-être temps d'essayer quelque chose d'autre comme CasperJS . Il fonctionne sur PhantomJS, mais possède une API bien meilleure pour naviguer dans les pages Web.

13
Artjom B.

Utilisez le wrapper de haut niveau, nightmarejs . Vous pouvez facilement click et attendre par la suite.

Voici le code (section Exemples):

var Nightmare = require('nightmare');
new Nightmare()
  .goto('http://yahoo.com')
    .type('input[title="Search"]', 'github nightmare')
    .click('.searchsubmit')
    .run(function (err, nightmare) {
      if (err) return console.log(err);
      console.log('Done!');
    });

Vous trouverez plus d’exemples et d’utilisation des API à l’adresse github

8
Grigorii Chudnov

Voici mon code basé sur d'autres réponses. Dans mon cas, je n'ai pas eu besoin d'évaluer spécifiquement un autre javascript. Je devais juste attendre que la page se termine.

var system = require('system');
if (system.args.length === 1) {
    console.log('Try to pass some arguments when invoking this script!');
}
else {
    var page = require('webpage').create();
    var address = system.args[1];

    page.open(address, function(status){
        page.onLoadFinished = function(status) {
            console.log(page.content);
            phantom.exit();
        };    
    });     
}

Enregistrez ce qui précède dans un fichier appelé "scrape.js" et appelez-le ainsi:

phantomjs --ssl-protocol=any --ignore-ssl-errors=true scrape.js https://www.example.com

Les paramètres liés à SSL sont ajoutés pour éviter d'autres problèmes que j'avais avec certains sites HTTPS (liés à des problèmes de chargement de certificat). 

J'espère que cela aide quelqu'un!

0
http203