Come inviare un modulo utilizzando PhantomJS


161

Sto cercando di usare phantomJS (che strumento fantastico tra cui!) Per inviare un modulo per una pagina per la quale ho le credenziali di accesso, e quindi inviare il contenuto della pagina di destinazione su stdout. Sono in grado di accedere al modulo e impostare i suoi valori con successo utilizzando Phantom, ma non sono sicuro di quale sia la sintassi corretta per inviare il modulo e produrre il contenuto della pagina successiva. Quello che ho finora è:

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="mylogin@somedomain.com";
          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();
}

Risposte:


229

L'avevo capito. Fondamentalmente è un problema asincrono. Non puoi semplicemente inviare e aspettarti di eseguire immediatamente il rendering della pagina successiva. Devi aspettare fino a quando l'evento onLoad per la pagina successiva viene attivato. Il mio codice è sotto:

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

3
questo è un ottimo modello. Ecco un paio di cose che ho aggiunto: setIntervaluso interno var func = steps[testindex], quindi console.log("step " + (testindex + 1) + ": " + funcName(func)). Ciò consente di aggiungere una descrizione ai passaggi eseguiti.
Jonno,

vedere qui per funcName. Inoltre ho trovato più facile sfogliare una serie di pagine Web e provare diverse tecniche per eseguire il rendering dell'ultima pagina page.render("output.png");.
Jonno,

2
Questo è un post davvero utile. Una domanda però. Quando si invia un modulo tramite POST, i dati vengono inviati al server e il server restituisce la risposta. Dov'è il codice in cui gestisci questa risposta o viene fatto automaticamente da phantomjs? Inoltre, dopo l'invio del modulo, un server può tornare COOKIEe la mia domanda è: * questo cookie è disponibile phantom.cookiesnell'oggetto quando il server restituisce la risposta * ?
MrD

usa CasperJS è meglio di PhantomJS, ha la capacità di postare su form senza codifica complessa
waza123


62

Inoltre, CasperJS offre un'interfaccia di alto livello per la navigazione in PhantomJS, incluso il clic sui collegamenti e la compilazione di moduli.

CasperJS

Aggiornato per aggiungere l' articolo del 28 luglio 2015 confrontando PhantomJS e CasperJS .

(Grazie al commentatore Mr. M!)


1
Casper non ha funzionato per me perché è possibile compilare un modulo solo usando il nome. Avevo bisogno di usare l'id.
user984003

4
@ user984003 Dovresti essere in grado di impostare il selettore #someidper compilare in base a un ID.
Arboc7,

2
CasperJS è una manna dal cielo! Rende la raschiatura delle pagine ASPX un gioco da ragazzi. Grazie!
Tobia,

@ user984003 Non so se stavi usando una versione precedente, ma quella corrente ha un fillSelectors () per riempire i campi del modulo usando qualsiasi selettore.
Tobia,

3
Chiunque usi PhantomJS dovrebbe iniziare a usare CasperJS. Ecco un post che descrive il perché: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MrD

19

L'invio di richieste POST non elaborate può talvolta essere più conveniente. Di seguito puoi vedere l' esempio originale di post.js da 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();
});

6
Attenzione, lettori, che eseguire le GETrichieste in modo simile (facendo qualcosa di simile page.open(server, 'get', data, ...) non funzionerà.
zbr,

7

Come accennato in precedenza, CasperJS è lo strumento migliore per compilare e inviare moduli. Il più semplice esempio possibile di come compilare e inviare il modulo utilizzando la funzione 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();
  });
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.