Comment attendre le chargement des pages lors de l'utilisation de casperjs?

J'essaie de gratter une page Web qui a une forme avec de nombreuses listes déroulantes et les valeurs dans la forme sont interdépendantes. À beaucoup de points, j'ai besoin du code pour attendre que l'actualisation de la page soit terminée. Par exemple, après avoir sélectionné une option dans la liste, le code doit attendre que la liste suivante soit remplie en fonction de cette sélection. Il serait vraiment utile que quelqu'un puisse donner des pointeurs car étrangement mon code ne fonctionne qu'après avoir donné tant d'instructions de journalisation inutiles qui à leur tour en ont créé retard. Toutes les suggestions pour améliorer le code seraient très utiles.

var casper = require('casper').create({
     verbose: true,
     logLevel: 'debug',
     userAgent: 'Mozilla/5.0  poi poi poi (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22',
     pageSettings: {}
 });

 casper.start('http://www.abc.com', function () {
     console.log("casper started");
     this.fill('form[action="http://www.abc.com/forum/member.php"]', {
         quick_username: "qwe",
         quick_password: "qwe"
     }, true);
     this.capture('screen.png');
 });
 casper.thenOpen("http://www.abc.com/search/index.php").then(function () {
     this.click('input[type="checkbox"][name="firstparam"]');
     this.click('a#poi');

     casper.evaluate(function () {
         document.getElementsByName("status")[0].value = 1;
         document.getElementsByName("state")[0].value = 1078;
         changeState(); //This function is associated with the dropdown ie state 
and the page reloads at this point. Only after complete refresh the code shoud execute! How can this be achieved?
         return true;
     });
     this.echo('Inside the first thenOpen' + this.evaluate(function () {
         return document.search.action;
     }));
 });
 casper.then(function () {
     this.capture("poi.png");
     console.log('just before injecting jquery');
     casper.page.injectJs('./jquery.js');
     this.click('input[type="checkbox"][name="or"]');
     this.evaluate(function () {
         $('.boxline .filelist input:checkbox[value=18127]').attr("checked", true);
     });
     this.echo('Just before pressing the add college button' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture('collegeticked.png');
     if (this.exists('input[type="button"][name="niv"]')) {
         this.echo('button is there');
     } else {
         this.echo('button is not there');
     }
     this.echo("Going to print return value");
     this.click('input[type="button"][name="poi"]'); // This click again causes a page refresh. Code should wait at this point for completion.
     this.echo('Immediately after pressing the add college btn getPresentState()' + this.evaluate(function () {
         return getPresentState();
     }));
     this.echo('Immediately after pressing add colleg button' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture('iu.png');
 });

 casper.then(function () {
     console.log('just before form submit');
     this.click('form[name="search"] input[type="submit"]'); //Again page refresh. Wait.
     this.echo('Immediately after search btn getPresentState()' + this.evaluate(function () {
         return getPresentState();
     }));
     this.echo('Immediately after search button-action' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture("mnf.png");
 });

 casper.then(function () {
     casper.page.injectJs('./jquery.js');
     this.capture("resultspage.png");

     this.echo('Page title is: ' + this.evaluate(function () {
         return document.title;
     }), 'INFO');
     var a = casper.evaluate(function () {
           return $('tbody tr td.tdbottom:contains("tye") ').siblings().filter($('td>a').parent());
     });
     console.log("ARBABU before" + a.length);
 });

 casper.run();
23
demandé sur qwerty123 2014-03-04 09:22:48

7 réponses

J'ai utilisé la 'solution de contournement' waitforselector mentionnée par Arun ici: https://stackoverflow.com/a/22217657/1842033

C'est la meilleure solution que j'ai trouvée; le 'inconvénient' est que vous devez être conscient de l'élément que vous attendez de charger. Je dis inconvénient, personnellement, je ne pense pas avoir rencontré une situation où je n'ai pas eu certains genre de rétroaction disant que tout ce que j'attends est arrivé

this.waitForSelector("{myElement}",
    function pass () {
        test.pass("Found {myElement}");
    },
    function fail () {
        test.fail("Did not load element {myElement}");
    },
    20000 // timeout limit in milliseconds
);

Bien que je suppose que vous pourriez utilisez waitForResource () ou quelque chose comme ça si vous n'avez pas de retour visuel.

10
répondu Algy Taylor 2017-05-23 11:53:17

Ce que j'ai pris à faire pour contourner ce problème, quand il n'y a rien de spécifique à cibler et attendre dans la page Rechargée, est d'utiliser ce qui suit:

var classname = 'reload-' + (new Date().getTime()),
    callback = function(){},
    timeout = function(){};

/// It happens when they change something...
casper.evaluate(function(classname){
  document.body.className += ' ' + classname;
}, classname);

casper.thenClick('#submit'); /// <-- will trigger a reload of the page
casper.waitWhileSelector('body.' + classname, callback, timeout);

De cette façon, je n'ai pas besoin de compter sur un élément attendu spécifique dans la page suivante, j'ai essentiellement fait l'inverse. J'ai créé un sélecteur spécifique à surveiller, et l'exécution se déplace une fois que ce sélecteur ne correspond pas.

Pour mes intentions, il suffisait de savoir que la page avait commencé à recharger, Je pas besoin d'attendre que la page suivante soit complètement rechargée. C'est pour que je puisse alors déclencher certains appels waitForSelector sur des éléments qui ont pu exister à la fois avant et après le rechargement. Attendre que la classe temporaire ait été supprimée me permet de savoir que tout ce qui existait auparavant a depuis été détruit, donc aucune crainte de sélectionner des éléments avant le rechargement.

7
répondu Pebbl 2014-11-10 16:41:36

Semble qu'il n'y a pas de vraies solutions. http://docs.casperjs.org/en/latest/modules/casper.html#waitforselector est une solution de contournement disponible qui peut ne pas fonctionner toujours.

2
répondu qwerty123 2014-03-06 07:16:07

J'ai la même expérience de faire la même chose que toi. script de cette façon dans la perspective de l'utilisateur n'a jamais bien passé. il s'écrase au milieu de nulle part et très peu fiable. Je faisais une recherche à partir de salesforce qui nécessite également une connexion.

Vous devez garder votre pas aussi minimum que possible. script en cron façon. ne faites pas de remplissage de formulaire / clic de bouton sauf si vous effectuez des tests D'interface utilisateur. Je vous conseille de diviser le processus en deux parties

// this part do search and find out the exact url of your screen capture.
// save it in a db/csv file
1 - start by POST to http://www.abc.com/forum/member.php with username password in body.
2 - POST/GET to http://www.abc.com/search/index.php with your search criteria, you look at what the website require. if they do POST, then POST.

// second part read your input
1 - login same as first part.
2 - casper forEach your input save your capture. (save the capture result in db/csv)

Mon script est maintenant pur phantomjs, casper script juste continuer à planter sans raison. même phantomjs n'est pas fiable. J'enregistre le résultat / statut à chaque recherche/téléchargement réussi, chaque fois qu'il y a une erreur, je quitte le script Sinon le reste du résultat est imprévisible(bon résultat dans chrome s'avère mauvais dans phantomjs).

1
répondu wayne 2014-03-04 06:42:54

J'ai trouvé cette question lors de la recherche d'une solution à un problème où l'action click() ou fill() recharge exactement les mêmes données dans un iframe enfant. Voici mon amélioration à Pebbl Réponse:

casper.clickAndUnload = function (click_selector, unload_selector, callback, timeout) {
    var classname = 'reload-' + (new Date().getTime());
    this.evaluate(function (unload_selector, classname) {
        $(unload_selector).addClass(classname);
    }, unload_selector, classname);

    this.thenClick(click_selector);
    this.waitWhileSelector(unload_selector + '.' + classname, callback, timeout);
};

casper.fillAndUnload = function (form_selector, data, unload_selector, callback, timeout) {
    var classname = 'reload-' + (new Date().getTime());
    this.evaluate(function (unload_selector, classname) {
        $(unload_selector).addClass(classname);
    }, unload_selector, classname);
    this.fill(form_selector, data, true);
    this.waitWhileSelector(unload_selector + '.' + classname, callback, timeout);
};

Cette solution suppose que page utilise jQuery. Il ne devrait pas être difficile de le modifier pour les pages qui ne le font pas. unload_selector est un élément qui devrait être rechargé après le clic ou la soumission du formulaire.

1
répondu Lukasz 2017-05-23 11:45:27

Comme Casperjs est écrit pour les développeurs, on s'attend à ce que L'on sache dans quel état la page chargée devrait être, et quels éléments devraient être disponibles pour définir un État chargé de page.

Une option consiste à vérifier la présence, par exemple, d'une ressource javascript chargée à la fin de la page.

Lors de l'exécution de tout type de test, les résultats doivent être reproductibles à chaque fois et l'idempotence est donc essentielle. Pour que cela se produise, le testeur doit être capable de contrôler le environnement suffisant pour que cela se produise.

0
répondu Lloyd Moore 2014-11-08 10:16:06

Simplement évaluer document.readyState pour être complete ou interactive. Puis il est chargé.

C'est une implémentation avec un while, mais peut-être peut-être être fait avec interval...

this.then(function () {
 while(this.evaluate(function () { return document.readyState != 'complete' && document.readyState != 'interactive'; })) {}
});
0
répondu Abel 2017-07-15 09:42:09