Cara mengirim formulir menggunakan PhantomJS

161

Saya mencoba menggunakan phantomJS (alat hebat apa btw!) Untuk mengirimkan formulir untuk halaman tempat saya memiliki kredensial masuk, dan kemudian menampilkan konten halaman tujuan ke stdout. Saya dapat mengakses formulir dan mengatur nilainya dengan sukses menggunakan phantom, tapi saya tidak begitu yakin apa sintaks yang tepat untuk mengirimkan formulir dan menampilkan konten halaman berikutnya. Sejauh ini yang saya miliki adalah:

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
sumber

Jawaban:

227

Saya menemukan jawabannya. Pada dasarnya ini adalah masalah async. Anda tidak bisa hanya mengirim dan berharap untuk merender halaman berikutnya dengan segera. Anda harus menunggu hingga acara onLoad untuk halaman berikutnya dipicu. Kode saya di bawah ini:

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
sumber
3
ini adalah templat yang bagus. Berikut adalah beberapa hal yang saya tambahkan: setIntervalgunakan di dalam var func = steps[testindex], lalu console.log("step " + (testindex + 1) + ": " + funcName(func)). Ini memungkinkan Anda untuk menambahkan deskripsi ke langkah-langkah yang dilakukan.
Jonno
lihat di sini untuk funcName. Saya juga merasa lebih mudah ketika melewati serangkaian halaman web, dan mencoba berbagai teknik, untuk merender halaman terakhir yang digunakan page.render("output.png");.
Jonno
2
Ini adalah posting yang sangat membantu. Namun satu pertanyaan. Saat Anda mengirimkan formulir menggunakan POST, data dikirim ke server, dan server mengembalikan respons. Di mana kode tempat Anda menangani respons ini atau secara otomatis dilakukan oleh phantomjs? Juga, setelah pengiriman formulir, server dapat kembali COOKIE, dan pertanyaan saya adalah: * apakah cookie ini tersedia di phantom.cookiesobjek ketika server mengembalikan respons * ?
MrD
menggunakan CasperJS lebih baik daripada PhantomJS, memiliki kemampuan untuk mengirim ke bentuk tanpa pengkodean kompleks
waza123
62

Juga, CasperJS menyediakan antarmuka tingkat tinggi yang bagus untuk navigasi di PhantomJS, termasuk mengklik tautan dan mengisi formulir.

CasperJS

Diperbarui untuk menambahkan 28 Juli 2015 artikel yang membandingkan PhantomJS dan CasperJS .

(Terima kasih kepada komentator Mr. M!)

arboc7
sumber
1
Casper tidak bekerja untuk saya karena Anda hanya bisa mengisi input formulir menggunakan nama. Saya perlu menggunakan id.
user984003
4
@ user984003 Anda harus dapat mengatur pemilih Anda #someiduntuk mengisi berdasarkan ID.
arboc7
2
CasperJS adalah anugerah! Itu membuat memo halaman ASPX mudah. Terima kasih!
Tobia
@ user984003 Saya tidak tahu apakah Anda menggunakan versi yang lebih lama, tetapi yang sekarang memiliki fillSelectors () untuk mengisi bidang formulir menggunakan pemilih apa pun.
Tobia
3
Siapa pun yang menggunakan PhantomJS harus mulai menggunakan CasperJS. Berikut adalah pos yang menjelaskan alasannya: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MrD
19

Mengirim permintaan POST mentah terkadang lebih nyaman. Di bawah ini Anda dapat melihat contoh asli post.js dari 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.
sumber
6
Sadarilah, pembaca, bahwa melakukan GETpermintaan serupa (dengan melakukan sesuatu seperti page.open(server, 'get', data, ...) tidak akan berhasil.
zbr
7

Seperti yang disebutkan di atas, CasperJS adalah alat terbaik untuk mengisi dan mengirim formulir. Contoh paling sederhana tentang cara mengisi & mengirim formulir menggunakan fungsi 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
sumber