So senden Sie ein Formular mit PhantomJS

161

Ich versuche, mit phantomJS (was übrigens ein großartiges Tool!) Ein Formular für eine Seite zu senden, für die ich Anmeldeinformationen habe, und dann den Inhalt der Zielseite an stdout auszugeben. Ich kann mit Phantom auf das Formular zugreifen und seine Werte erfolgreich festlegen, bin mir jedoch nicht ganz sicher, wie die richtige Syntax lautet, um das Formular zu senden und den Inhalt der nachfolgenden Seite auszugeben. Was ich bisher habe ist:

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
quelle

Antworten:

227

Ich habe es herausgefunden. Grundsätzlich ist es ein asynchrones Problem. Sie können nicht einfach einreichen und erwarten, dass die nachfolgende Seite sofort gerendert wird. Sie müssen warten, bis das Ereignis onLoad für die nächste Seite ausgelöst wird. Mein Code ist unten:

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
quelle
3
Dies ist eine großartige Vorlage. Hier sind ein paar Dinge , die ich hinzugefügt: im setIntervalEinsatz var func = steps[testindex], dann console.log("step " + (testindex + 1) + ": " + funcName(func)). Auf diese Weise können Sie den ausgeführten Schritten eine Beschreibung hinzufügen.
Jonno
siehe hier für funcName. Außerdem fand ich es einfacher, eine Reihe von Webseiten durchzugehen und verschiedene Techniken auszuprobieren, um die letzte Seite mit zu rendern page.render("output.png");.
Jonno
2
Dies ist ein wirklich hilfreicher Beitrag. Eine Frage allerdings. Wenn Sie ein Formular mit POST senden, werden Daten an den Server gesendet und der Server gibt eine Antwort zurück. Wo ist der Code, in dem Sie diese Antwort verarbeiten, oder er wird automatisch von Phantomjs ausgeführt? Nach dem Einreichen des Formulars kann ein Server zurückkehren COOKIE. Meine Frage lautet: *phantom.cookies Ist dieses Cookie im Objekt verfügbar, wenn der Server eine Antwort zurückgibt * ?
MrD
Verwenden Sie CasperJS, es ist besser als PhantomJS, es kann auf Formularen ohne komplexe Codierung
posten
Könnten Sie bitte auch dies überprüfen stackoverflow.com/questions/44624964/phantom-js-on-web-project
Manik
62

Außerdem bietet CasperJS eine schöne allgemeine Benutzeroberfläche für die Navigation in PhantomJS, einschließlich Klicken auf Links und Ausfüllen von Formularen.

CasperJS

Aktualisiert, um einen Artikel vom 28. Juli 2015 hinzuzufügen , in dem PhantomJS und CasperJS verglichen werden .

(Danke an Kommentator Mr. M!)

arboc7
quelle
1
Casper hat bei mir nicht funktioniert, da Sie eine Formulareingabe nur mit dem Namen ausfüllen konnten. Ich musste id verwenden.
user984003
4
@ user984003 Sie sollten in der Lage sein, Ihren Selektor so einzustellen, dass #someider basierend auf einer ID ausgefüllt wird .
Arboc7
2
CasperJS ist ein Glücksfall! Das Scrapen von ASPX-Seiten wird zum Kinderspiel. Danke dir!
Tobia
@ user984003 Ich weiß nicht, ob Sie eine ältere Version verwendet haben, aber die aktuelle hat ein fillSelectors (), um Formularfelder mit einem beliebigen Selektor zu füllen.
Tobia
3
Jeder, der PhantomJS verwendet, sollte CasperJS verwenden. Hier ist ein Beitrag, der beschreibt, warum: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MrD
19

Das Senden von rohen POST-Anforderungen kann manchmal bequemer sein. Unten sehen Sie das Originalbeispiel von post.j von 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.
quelle
6
Seien Sie sich bewusst, Leser, dass es nicht funktioniert , GETAnfragen ähnlich auszuführen (indem Sie so etwas tun page.open(server, 'get', data, ...).
zbr
7

Wie oben erwähnt, ist CasperJS das beste Werkzeug zum Ausfüllen und Senden von Formularen. Einfachstes Beispiel für das Ausfüllen und Senden eines Formulars mit der Funktion 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
quelle