วิธีการส่งแบบฟอร์มโดยใช้ PhantomJS


161

ฉันพยายามใช้ phantomJS (เป็นเครื่องมือที่ยอดเยี่ยม btw!) เพื่อส่งแบบฟอร์มสำหรับหน้าเว็บที่ฉันมีข้อมูลประจำตัวสำหรับเข้าสู่ระบบจากนั้นส่งออกเนื้อหาของหน้าปลายทางไปยัง stdout ฉันสามารถเข้าถึงฟอร์มและตั้งค่าเรียบร้อยแล้วโดยใช้ phantom แต่ฉันไม่แน่ใจว่าสิ่งที่ไวยากรณ์ที่ถูกต้องคือการส่งแบบฟอร์มและส่งออกเนื้อหาของหน้าถัดไป สิ่งที่ฉันมีอยู่คือ:

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

คำตอบ:


227

ฉันคิดออก โดยทั่วไปมันเป็นปัญหาของการซิงค์ คุณไม่สามารถส่งและคาดว่าจะแสดงหน้าต่อไปได้ทันที คุณต้องรอจนกว่าจะมีการเรียกใช้กิจกรรม onLoad สำหรับหน้าถัดไป รหัสของฉันอยู่ด้านล่าง:

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
นี่คือเทมเพลตที่ยอดเยี่ยม นี่คือคู่ของสิ่งที่ฉันเพิ่ม: ภายในsetIntervalการใช้งานแล้วvar func = steps[testindex] console.log("step " + (testindex + 1) + ": " + funcName(func))สิ่งนี้อนุญาตให้คุณเพิ่มคำอธิบายลงในขั้นตอนที่กำลังดำเนินการ
Jonno

ดูที่นี่funcNameสำหรับ page.render("output.png");นอกจากนี้ผมพบว่ามันง่ายเมื่อไปผ่านชุดของหน้าเว็บและพยายามเทคนิคที่แตกต่างกันในการแสดงผลหน้าสุดท้ายที่ใช้
Jonno

2
โพสต์นี้เป็นประโยชน์จริงๆ แม้ว่าหนึ่งคำถาม เมื่อคุณส่งแบบฟอร์มโดยใช้ POST ข้อมูลจะถูกส่งไปยังเซิร์ฟเวอร์และเซิร์ฟเวอร์จะตอบกลับ รหัสที่คุณจัดการกับการตอบสนองนี้อยู่ที่ไหนหรือจะทำโดย phantomjs โดยอัตโนมัติ? นอกจากนี้หลังจากที่รูปแบบ submition เซิร์ฟเวอร์สามารถกลับCOOKIEและคำถามของฉันคือ* เป็นคุกกี้นี้ที่มีอยู่ในphantom.cookiesวัตถุเมื่อการตอบสนองผลตอบแทนเซิร์ฟเวอร์ * ?
MrD

ใช้ CasperJS มันดีกว่า PhantomJS มันมีความสามารถในการโพสต์ไปยังแบบฟอร์มโดยไม่ต้องเขียนโค้ดที่ซับซ้อน
waza123


62

นอกจากนี้ CasperJS ยังมีอินเทอร์เฟซระดับสูงสำหรับการนำทางใน PhantomJS รวมถึงการคลิกที่ลิงก์และกรอกแบบฟอร์ม

CasperJS

การปรับปรุงเพื่อเพิ่ม28 กรกฎาคม 2015 บทความเปรียบเทียบ PhantomJS และ CasperJS

(ขอบคุณผู้วิจารณ์ Mr. M!)


1
แคสเปอร์ไม่ได้ผลสำหรับฉันเพราะคุณทำได้เพียงกรอกแบบฟอร์มโดยใช้ชื่อ ฉันต้องใช้รหัส
user984003

4
@ user984003 คุณควรจะสามารถตั้งค่าตัวเลือกของคุณ#someidเพื่อกรอกตาม ID
arboc7

2
CasperJS คือสวรรค์! มันทำให้การขูดหน้า ASPX เป็นเรื่องง่าย ขอบคุณ!
Tobia

@ user984003 ฉันไม่รู้ว่าคุณใช้เวอร์ชั่นเก่ากว่าหรือไม่ แต่ปัจจุบันมี fillSelectors () เพื่อกรอกข้อมูลในฟิลด์โดยใช้ตัวเลือกใด ๆ
Tobia

3
ทุกคนที่ใช้ PhantomJS ควรเริ่มใช้ CasperJS นี่คือการโพสต์อธิบายว่าทำไม: code-epicenter.com/why-is-casperjs-better-than-phantomjs
MRD

19

การส่งคำขอ POST แบบดิบอาจสะดวกกว่าในบางครั้ง ด้านล่างคุณสามารถดูตัวอย่างต้นฉบับของ post.js จาก 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
ระวังผู้อ่านที่ดำเนินการGETตามคำขอในทำนองเดียวกัน (โดยทำสิ่งที่ชอบpage.open(server, 'get', data, ...) จะไม่ทำงาน
zbr

7

ตามที่กล่าวไว้ข้างต้นCasperJSเป็นเครื่องมือที่ดีที่สุดในการกรอกและส่งแบบฟอร์ม ตัวอย่างที่เป็นไปได้ที่ง่ายที่สุดในการกรอก & ส่งแบบฟอร์มโดยใช้ฟังก์ชั่นเติม () :

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();
  });
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.