Comment soumettre un formulaire à l'aide de PhantomJS

161

J'essaie d'utiliser phantomJS (quel outil génial btw!) Pour soumettre un formulaire pour une page pour laquelle j'ai des informations de connexion, puis afficher le contenu de la page de destination vers stdout. Je suis capable d'accéder au formulaire et de définir ses valeurs avec succès en utilisant fantôme, mais je ne suis pas tout à fait sûr de la bonne syntaxe pour soumettre le formulaire et afficher le contenu de la page suivante. Ce que j'ai jusqu'à présent, c'est:

var page = new WebPage();
var url = phantom.args[0];

page.open(url, function (status) {

  if (status !== 'success') {
      console.log('Unable to access network');
  } else {

    console.log(page.evaluate(function () {

      var arr = document.getElementsByClassName("login-form");
      var i;

      for (i=0; i < arr.length; i++) {

        if (arr[i].getAttribute('method') == "POST") {
          arr[i].elements["email"].value="[email protected]";
          arr[i].elements["password"].value="mypassword";

          // This part doesn't seem to work. It returns the content
          // of the current page, not the content of the page after 
          // the submit has been executed. Am I correctly instrumenting
          // the submit in Phantom?
          arr[i].submit();
          return document.querySelectorAll('html')[0].outerHTML;
        }

      }

      return "failed :-(";

    }));
  }

  phantom.exit();
}
Vijay Boyapati
la source

Réponses:

229

Je l'ai compris. En gros, c'est un problème asynchrone. Vous ne pouvez pas simplement soumettre et espérer rendre la page suivante immédiatement. Vous devez attendre le déclenchement de l'événement onLoad de la page suivante. Mon code est ci-dessous:

var page = new WebPage(), testindex = 0, loadInProgress = false;

page.onConsoleMessage = function(msg) {
  console.log(msg);
};

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

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

var steps = [
  function() {
    //Load Login Page
    page.open("https://website.com/theformpage/");
  },
  function() {
    //Enter Credentials
    page.evaluate(function() {

      var arr = document.getElementsByClassName("login-form");
      var i;

      for (i=0; i < arr.length; i++) { 
        if (arr[i].getAttribute('method') == "POST") {

          arr[i].elements["email"].value="mylogin";
          arr[i].elements["password"].value="mypassword";
          return;
        }
      }
    });
  }, 
  function() {
    //Login
    page.evaluate(function() {
      var arr = document.getElementsByClassName("login-form");
      var i;

      for (i=0; i < arr.length; i++) {
        if (arr[i].getAttribute('method') == "POST") {
          arr[i].submit();
          return;
        }
      }

    });
  }, 
  function() {
    // Output content of page to stdout after form has been submitted
    page.evaluate(function() {
      console.log(document.querySelectorAll('html')[0].outerHTML);
    });
  }
];


interval = setInterval(function() {
  if (!loadInProgress && typeof steps[testindex] == "function") {
    console.log("step " + (testindex + 1));
    steps[testindex]();
    testindex++;
  }
  if (typeof steps[testindex] != "function") {
    console.log("test complete!");
    phantom.exit();
  }
}, 50);
Vijay Boyapati
la source
3
c'est un excellent modèle. Voici quelques éléments que j'ai ajoutés: l' setIntervalutilisation interne var func = steps[testindex], alors console.log("step " + (testindex + 1) + ": " + funcName(func)). Cela vous permet d'ajouter une description aux étapes en cours d'exécution.
Jonno
voir ici pour funcName. J'ai également trouvé plus facile en parcourant une série de pages Web et en essayant différentes techniques de rendre la dernière page en utilisant page.render("output.png");.
Jonno
2
C'est un article vraiment utile. Une question cependant. Lorsque vous soumettez un formulaire à l'aide du POST, les données sont envoyées au serveur et le serveur renvoie une réponse. Où est le code où vous gérez cette réponse ou est-ce automatiquement fait par phantomjs? De plus, après la soumission du formulaire, un serveur peut retourner COOKIE, et ma question est: * ce cookie est-il disponible dans l' phantom.cookiesobjet lorsque le serveur renvoie la réponse * ?
MrD
utiliser CasperJS c'est mieux que PhantomJS, il a la capacité de publier sur des formulaires sans codage complexe
waza123
Pourriez-vous s'il vous plaît vérifier cela aussi stackoverflow.com/questions/44624964/phantom-js-on-web-project
Manik
62

En outre, CasperJS fournit une belle interface de haut niveau pour la navigation dans PhantomJS, notamment en cliquant sur des liens et en remplissant des formulaires.

CasperJS

Mis à jour pour ajouter un article du 28 juillet 2015 comparant PhantomJS et CasperJS .

(Merci au commentateur M. M!)

arboc7
la source
1
Casper n'a pas fonctionné pour moi car vous ne pouviez remplir qu'un formulaire en utilisant le nom. J'avais besoin d'utiliser id.
user984003
4
@ user984003 Vous devriez pouvoir régler votre sélecteur sur #someidà remplir en fonction d'un ID.
arboc7
2
CasperJS est une aubaine! Cela permet de gratter les pages ASPX en un tournemain. Je vous remercie!
Tobia
@ user984003 Je ne sais pas si vous utilisiez une version plus ancienne, mais l'actuelle a un fillSelectors () pour remplir les champs du formulaire en utilisant n'importe quel sélecteur.
Tobia
3
Quiconque utilise PhantomJS devrait commencer à utiliser CasperJS. Voici un article décrivant pourquoi: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MrD
19

L'envoi de requêtes POST brutes peut être parfois plus pratique. Ci-dessous vous pouvez voir l'exemple original post.js de PhantomJS

// Example using HTTP POST operation

var page = require('webpage').create(),
    server = 'http://posttestserver.com/post.php?dump',
    data = 'universe=expanding&answer=42';

page.open(server, 'post', data, function (status) {
    if (status !== 'success') {
        console.log('Unable to post!');
    } else {
        console.log(page.content);
    }
    phantom.exit();
});
Jakub M.
la source
6
Sachez, lecteurs, que l'exécution des GETrequêtes de la même manière (en faisant quelque chose comme page.open(server, 'get', data, ...) ne fonctionnera pas.
zbr
7

Comme mentionné ci-dessus, CasperJS est le meilleur outil pour remplir et envoyer des formulaires. Exemple le plus simple possible de comment remplir et soumettre un formulaire en utilisant la fonction fill () :

casper.start("http://example.com/login", function() {
//searches and fills the form with id="loginForm"
  this.fill('form#loginForm', {
    'login':    'admin',
    'password':    '12345678'
   }, true);
  this.evaluate(function(){
    //trigger click event on submit button
    document.querySelector('input[type="submit"]').click();
  });
});
DominikStyp
la source