Cómo enviar un formulario usando PhantomJS

161

Estoy tratando de usar phantomJS (¡qué herramienta increíble por cierto!) Para enviar un formulario para una página para la que tengo credenciales de inicio de sesión, y luego enviar el contenido de la página de destino a stdout. Puedo acceder al formulario y establecer sus valores con éxito usando phantom, pero no estoy muy seguro de cuál es la sintaxis correcta para enviar el formulario y generar el contenido de la página siguiente. Lo que tengo hasta ahora es:

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
fuente

Respuestas:

227

Me lo imaginé. Básicamente es un problema asíncrono. No puede simplemente enviar y esperar representar la página siguiente de inmediato. Debe esperar hasta que se active el evento onLoad para la siguiente página. Mi código está abajo:

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
fuente
3
Esta es una gran plantilla. Aquí hay un par de cosas que agregué: setIntervaluso interno var func = steps[testindex], entonces console.log("step " + (testindex + 1) + ": " + funcName(func)). Esto le permite agregar una descripción a los pasos que se realizan.
Jonno
mira aquí para funcName. También me resultó más fácil cuando revisé una serie de páginas web y probé diferentes técnicas para representar la última página usando page.render("output.png");.
Jonno
2
Esta es una publicación realmente útil. Una pregunta sin embargo. Cuando envía un formulario utilizando POST, los datos se envían al servidor y el servidor devuelve la respuesta. ¿Dónde está el código en el que manejas esta respuesta o phantomjs lo hace automáticamente? Además, después de la presentación del formulario, un servidor puede regresar COOKIE, y mi pregunta es: * ¿esta cookie está disponible en el phantom.cookiesobjeto cuando el servidor devuelve la respuesta * ?
MrD
usar CasperJS es mejor que PhantomJS, tiene la capacidad de publicar en formularios sin codificación compleja
waza123
¿Podría comprobar esto también? Stackoverflow.com/questions/44624964/phantom-js-on-web-project
Manik
62

Además, CasperJS proporciona una agradable interfaz de alto nivel para la navegación en PhantomJS, que incluye hacer clic en enlaces y completar formularios.

CasperJS

Actualizado para agregar el artículo del 28 de julio de 2015 que compara PhantomJS y CasperJS .

(¡Gracias al comentarista Sr. M!)

arboc7
fuente
1
Casper no funcionó para mí porque solo podía completar una entrada de formulario con nombre. Necesitaba usar la identificación.
user984003
44
@ user984003 Debería poder configurar su selector para #someidque se complete en función de una ID.
arboc7 01 de
2
CasperJS es un regalo del cielo! Hace que raspar páginas ASPX sea muy fácil. ¡Gracias!
Tobia
@ user984003 No sé si estaba usando una versión anterior, pero la actual tiene un FillSelectors () para llenar los campos del formulario usando cualquier selector.
Tobia
3
Cualquiera que esté usando PhantomJS debería comenzar a usar CasperJS. Aquí hay una publicación que describe por qué: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MrD
19

Enviar solicitudes POST sin procesar a veces puede ser más conveniente. A continuación puede ver el ejemplo original de 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.
fuente
66
Tenga en cuenta, lectores, que realizar GETsolicitudes de manera similar (haciendo algo como page.open(server, 'get', data, ...) no funcionará.
zbr
7

Como se mencionó anteriormente, CasperJS es la mejor herramienta para llenar y enviar formularios. El ejemplo más simple posible de cómo llenar y enviar un formulario usando la función 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
fuente