แฟนทอมไม่รอโหลดหน้าเว็บเต็ม


137

ฉันใช้PhantomJS v1.4.1 เพื่อโหลดหน้าเว็บบางหน้า ฉันไม่สามารถเข้าถึงฝั่งเซิร์ฟเวอร์ของพวกเขาฉันเพิ่งได้รับลิงก์ชี้ไปที่พวกเขา ฉันกำลังใช้ Phantom เวอร์ชันล้าสมัยเพราะฉันต้องการการสนับสนุน Adobe Flash บนหน้าเว็บนั้น

ปัญหาคือเว็บไซต์จำนวนมากโหลด async เนื้อหารองของพวกเขาและนั่นเป็นสาเหตุที่ Phantom เรียกคืน onLoadFinished โทรกลับ (อะนาล็อกสำหรับ onLoad ใน HTML) เริ่มต้นเร็วเกินไปเมื่อทุกอย่างยังไม่โหลด ใครสามารถแนะนำฉันจะรอโหลดหน้าเว็บเต็มหน้าจอตัวอย่างเช่นภาพหน้าจอที่มีเนื้อหาแบบไดนามิกทั้งหมดเช่นโฆษณาได้หรือไม่


3
ฉันคิดว่าถึงเวลายอมรับคำตอบแล้ว
spartikus

คำตอบ:


76

อีกวิธีหนึ่งคือขอให้ PhantomJS รอสักครู่หลังจากโหลดหน้าเว็บก่อนที่จะทำการเรนเดอร์ตามตัวอย่างrasterize.jsปกติแต่ใช้เวลานานกว่านั้นเพื่อให้ JavaScript โหลดทรัพยากรเพิ่มเติมให้เสร็จ:

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit();
    } else {
        window.setTimeout(function () {
            page.render(output);
            phantom.exit();
        }, 1000); // Change timeout as required to allow sufficient time 
    }
});

1
ใช่ปัจจุบันฉันติดกับวิธีนี้
nilfalse

102
มันเป็นทางออกที่น่ากลัวขอโทษ (มันเป็นความผิดของ PhantomJS!) ถ้าคุณรอวินาทีเต็ม แต่ใช้เวลาโหลด 20ms มันเป็นการเสียเวลาโดยสมบูรณ์ (คิดว่าเป็นงานแบ็ตช์) หรือถ้าใช้เวลานานกว่าวินาทีมันจะยังคงล้มเหลว ความไร้ประสิทธิภาพและความไม่น่าเชื่อถือดังกล่าวไม่สามารถทำได้สำหรับงานมืออาชีพ
CodeManX

9
ปัญหาที่แท้จริงคือคุณไม่เคยรู้เลยว่าเมื่อไรจาวาสคริปต์จะเสร็จสิ้นการโหลดหน้าเว็บและเบราว์เซอร์ก็ไม่ทราบเช่นกัน ลองนึกภาพไซต์ที่มีจาวาสคริปต์บางตัวกำลังโหลดบางอย่างจากเซิร์ฟเวอร์ในวงวนไม่สิ้นสุด จากมุมมองของเบราว์เซอร์ - การประมวลผลจาวาสคริปต์จะไม่มีวันสิ้นสุดดังนั้นช่วงเวลาที่คุณต้องการให้ phantomjs บอกคุณว่าเสร็จสิ้นแล้ว ปัญหานี้แก้ไม่ได้ในกรณีทั่วไปยกเว้นรอการแก้ปัญหาการหมดเวลาและหวังว่าจะดีที่สุด
Maxim Galushka

5
นี่เป็นทางออกที่ดีที่สุดในปี 2559 หรือไม่? ดูเหมือนว่าเราน่าจะทำได้ดีกว่านี้
Adam Thompson

6
หากคุณเป็นผู้ควบคุมรหัสที่คุณพยายามอ่านคุณสามารถโทรไปที่ phantom js โทรกลับอย่างชัดเจน: phantomjs.org/api/webpage/handler/on-callback.html
Andy Smith

52

ฉันต้องการตรวจสอบdocument.readyStateสถานะเป็นระยะ ๆ( https://developer.mozilla.org/en-US/docs/Web/API/document.readyState ) แม้ว่าวิธีการนี้จะค่อนข้าง clunky คุณสามารถมั่นใจได้ว่าภายในonPageReadyฟังก์ชั่นที่คุณใช้เอกสารที่โหลดเต็ม

var page = require("webpage").create(),
    url = "http://example.com/index.html";

function onPageReady() {
    var htmlContent = page.evaluate(function () {
        return document.documentElement.outerHTML;
    });

    console.log(htmlContent);

    phantom.exit();
}

page.open(url, function (status) {
    function checkReadyState() {
        setTimeout(function () {
            var readyState = page.evaluate(function () {
                return document.readyState;
            });

            if ("complete" === readyState) {
                onPageReady();
            } else {
                checkReadyState();
            }
        });
    }

    checkReadyState();
});

คำอธิบายเพิ่มเติม:

การใช้การซ้อนกันsetTimeoutแทนการsetIntervalป้องกันcheckReadyStateจาก "การทับซ้อน" และเงื่อนไขการแข่งขันเมื่อการดำเนินการถูกยืดเยื้อด้วยเหตุผลบางอย่างแบบสุ่ม setTimeoutมีการหน่วงเวลาเริ่มต้นที่ 4ms ( https://stackoverflow.com/a/3580085/1011156 ) ดังนั้นการลงคะแนนแบบแอคทีฟจะไม่ส่งผลกระทบต่อประสิทธิภาพของโปรแกรมอย่างมาก

document.readyState === "complete"หมายความว่าเอกสารนั้นเต็มไปด้วยทรัพยากรทั้งหมดอย่างสมบูรณ์ ( https://html.spec.whatwg.org/multipage/dom.html#current-document-readiness )


4
ความคิดเห็นที่ setTimeout เทียบกับ setInterval นั้นยอดเยี่ยม
Gal Bracha

1
readyStateจะทริกเกอร์เมื่อ DOM โหลดเต็มแล้วเท่านั้นอย่างไรก็ตาม<iframe>องค์ประกอบใด ๆอาจยังโหลดอยู่ดังนั้นจึงไม่ตอบคำถามเดิมจริงๆ
CodingIntrigue

1
@rgraham มันไม่เหมาะ แต่ฉันคิดว่าเราทำได้แค่กับผู้สร้างภาพเหล่านี้เท่านั้น จะมีกรณีขอบที่คุณเพิ่งจะไม่รู้ว่ามีบางอย่างเต็ม คิดเกี่ยวกับหน้าเว็บที่มีเนื้อหาล่าช้าตามวัตถุประสงค์ประมาณหนึ่งหรือสองนาที ไม่มีเหตุผลที่คาดว่ากระบวนการเรนเดอร์จะนั่งรอเวลาที่กำหนด เช่นเดียวกันกับเนื้อหาที่โหลดจากแหล่งภายนอกที่อาจช้า
Brandon Elliott

3
สิ่งนี้ไม่ถือว่าการโหลด JavaScript หลังจาก DOM โหลดเต็มเช่นกับ Backbone / Ember / Angular
Adam Thompson

1
ไม่ได้ผลเลยสำหรับฉัน readyState เสร็จสมบูรณ์อาจจะถูกไล่ออก แต่หน้าว่างเปล่า ณ จุดนี้
Steve Staple

21

คุณสามารถลองตัวอย่าง waitfor และ rasterize:

/**
 * See https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js
 * 
 * Wait until the test condition is true or a timeout occurs. Useful for waiting
 * on a server response or for a ui change (fadeIn, etc.) to occur.
 *
 * @param testFx javascript condition that evaluates to a boolean,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param onReady what to do when testFx condition is fulfilled,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
 */
function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()), //< defensive code
        interval = setInterval(function() {
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if(!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};

var page = require('webpage').create(), system = require('system'), address, output, size;

if (system.args.length < 3 || system.args.length > 5) {
    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    phantom.exit(1);
} else {
    address = system.args[1];
    output = system.args[2];
    if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
        size = system.args[3].split('*');
        page.paperSize = size.length === 2 ? {
            width : size[0],
            height : size[1],
            margin : '0px'
        } : {
            format : system.args[3],
            orientation : 'portrait',
            margin : {
                left : "5mm",
                top : "8mm",
                right : "5mm",
                bottom : "9mm"
            }
        };
    }
    if (system.args.length > 4) {
        page.zoomFactor = system.args[4];
    }
    var resources = [];
    page.onResourceRequested = function(request) {
        resources[request.id] = request.stage;
    };
    page.onResourceReceived = function(response) {
        resources[response.id] = response.stage;
    };
    page.open(address, function(status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit();
        } else {
            waitFor(function() {
                // Check in the page if a specific element is now visible
                for ( var i = 1; i < resources.length; ++i) {
                    if (resources[i] != 'end') {
                        return false;
                    }
                }
                return true;
            }, function() {
               page.render(output);
               phantom.exit();
            }, 10000);
        }
    });
}

3
ดูเหมือนว่ามันจะไม่ทำงานกับเว็บเพจที่ใช้เทคโนโลยีพุชเซิร์ฟเวอร์ใด ๆ เนื่องจากทรัพยากรจะยังคงถูกใช้งานหลังจากที่เกิดขึ้นเมื่อโหลด
nilfalse

ทำไดรเวอร์ใด ๆ เช่น poltergeistมีคุณสมบัติเช่นนี้หรือไม่?
Jared Beck

เป็นไปได้ไหมที่จะใช้ waitFor ในการสำรวจข้อความ html ทั้งหมดและค้นหาคำหลักที่กำหนด? ฉันพยายามใช้สิ่งนี้ แต่ดูเหมือนว่าการสำรวจจะไม่รีเฟรชเป็นแหล่ง html ที่ดาวน์โหลดล่าสุด
fpdragon

14

บางทีคุณสามารถใช้onResourceRequestedและการonResourceReceivedเรียกกลับเพื่อตรวจสอบการโหลดแบบอะซิงโครนัส นี่คือตัวอย่างของการใช้การเรียกกลับเหล่านั้นจากเอกสารประกอบ :

var page = require('webpage').create();
page.onResourceRequested = function (request) {
    console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function (response) {
    console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
page.open(url);

นอกจากนี้คุณสามารถดูexamples/netsniff.jsตัวอย่างการทำงานได้


แต่ในกรณีนี้ฉันไม่สามารถใช้ PhantomJS หนึ่งอินสแตนซ์เพื่อโหลดมากกว่าหนึ่งหน้าในเวลาเดียวกันใช่ไหม
nilfalse

onResourceRequested ใช้กับคำขอ AJAX / Cross Domain หรือไม่ หรือมันใช้เฉพาะกับเช่น CSS, รูปภาพ .. ฯลฯ ?
CMCDragonkai

@CMCDragonkai ฉันไม่เคยใช้มันเอง แต่อยู่บนพื้นฐานนี้ดูเหมือนว่าจะมีการร้องขอทั้งหมด อ้างอิง:All the resource requests and responses can be sniffed using onResourceRequested and onResourceReceived
Supr

ฉันใช้วิธีนี้กับการแสดงผล PhantomJS ขนาดใหญ่และทำงานได้ค่อนข้างดี คุณจำเป็นต้องมีสมาร์ทมากในการติดตามคำขอและดูว่าพวกเขาล้มเหลวหรือหมดเวลา ข้อมูลเพิ่มเติม: sorcery.smugmug.com/2013/12/17/using-phantomjs-at-scale
Ryan Doherty

14

นี่คือวิธีแก้ปัญหาที่รอการร้องขอทรัพยากรทั้งหมดให้เสร็จสมบูรณ์ เมื่อเสร็จแล้วมันจะบันทึกเนื้อหาของหน้าไปยังคอนโซลและสร้างภาพหน้าจอของหน้าที่แสดงผล

แม้ว่าวิธีนี้จะเป็นจุดเริ่มต้นที่ดี แต่ฉันสังเกตว่ามันล้มเหลวดังนั้นมันจึงไม่ใช่ทางออกที่สมบูรณ์!

document.readyStateฉันไม่ได้มีโชคดีมากใช้

ผมได้รับอิทธิพลจากwaitfor.jsตัวอย่างพบได้บนหน้า phantomjs ตัวอย่าง

var system = require('system');
var webPage = require('webpage');

var page = webPage.create();
var url = system.args[1];

page.viewportSize = {
  width: 1280,
  height: 720
};

var requestsArray = [];

page.onResourceRequested = function(requestData, networkRequest) {
  requestsArray.push(requestData.id);
};

page.onResourceReceived = function(response) {
  var index = requestsArray.indexOf(response.id);
  requestsArray.splice(index, 1);
};

page.open(url, function(status) {

  var interval = setInterval(function () {

    if (requestsArray.length === 0) {

      clearInterval(interval);
      var content = page.content;
      console.log(content);
      page.render('yourLoadedPage.png');
      phantom.exit();
    }
  }, 500);
});

ยกนิ้วให้ แต่ใช้ setTimeout กับ 10 แทนช่วงเวลา
GDmac

คุณควรตรวจสอบว่า response.stage เท่ากับ 'สิ้นสุด' ก่อนที่จะลบออกจากอาร์เรย์คำขอมิฉะนั้นอาจถูกลบออกก่อนเวลาอันควร
คืนชีพ

สิ่งนี้จะไม่ทำงานหากเว็บเพจของคุณโหลด DOM แบบไดนามิก
Buddy

13

ในโปรแกรมของฉันฉันใช้ตรรกะบางอย่างเพื่อตัดสินว่าเป็น onload: ดูเป็นคำขอเครือข่ายหากไม่มีคำขอใหม่ใน 200ms ที่ผ่านมาฉันจัดการกับ onload

ใช้สิ่งนี้หลังจาก onLoadFinish ()

function onLoadComplete(page, callback){
    var waiting = [];  // request id
    var interval = 200;  //ms time waiting new request
    var timer = setTimeout( timeout, interval);
    var max_retry = 3;  //
    var counter_retry = 0;

    function timeout(){
        if(waiting.length && counter_retry < max_retry){
            timer = setTimeout( timeout, interval);
            counter_retry++;
            return;
        }else{
            try{
                callback(null, page);
            }catch(e){}
        }
    }

    //for debug, log time cost
    var tlogger = {};

    bindEvent(page, 'request', function(req){
        waiting.push(req.id);
    });

    bindEvent(page, 'receive', function (res) {
        var cT = res.contentType;
        if(!cT){
            console.log('[contentType] ', cT, ' [url] ', res.url);
        }
        if(!cT) return remove(res.id);
        if(cT.indexOf('application') * cT.indexOf('text') != 0) return remove(res.id);

        if (res.stage === 'start') {
            console.log('!!received start: ', res.id);
            //console.log( JSON.stringify(res) );
            tlogger[res.id] = new Date();
        }else if (res.stage === 'end') {
            console.log('!!received end: ', res.id, (new Date() - tlogger[res.id]) );
            //console.log( JSON.stringify(res) );
            remove(res.id);

            clearTimeout(timer);
            timer = setTimeout(timeout, interval);
        }

    });

    bindEvent(page, 'error', function(err){
        remove(err.id);
        if(waiting.length === 0){
            counter_retry = 0;
        }
    });

    function remove(id){
        var i = waiting.indexOf( id );
        if(i < 0){
            return;
        }else{
            waiting.splice(i,1);
        }
    }

    function bindEvent(page, evt, cb){
        switch(evt){
            case 'request':
                page.onResourceRequested = cb;
                break;
            case 'receive':
                page.onResourceReceived = cb;
                break;
            case 'error':
                page.onResourceError = cb;
                break;
            case 'timeout':
                page.onResourceTimeout = cb;
                break;
        }
    }
}

11

ฉันพบว่าวิธีนี้มีประโยชน์ในบางกรณี:

page.onConsoleMessage(function(msg) {
  // do something e.g. page.render
});

กว่าถ้าคุณเป็นเจ้าของหน้าใส่สคริปต์บางอย่างภายใน:

<script>
  window.onload = function(){
    console.log('page loaded');
  }
</script>

ดูเหมือนว่าเป็นการทำงานที่ดีจริงๆ แต่ฉันไม่สามารถรับข้อความบันทึกใด ๆ จากหน้า HTML / JavaScript ของฉันเพื่อส่งผ่าน phantomJS ... เหตุการณ์ onConsoleMessage ไม่เคยทำงานในขณะที่ฉันเห็นข้อความบนคอนโซลเบราว์เซอร์และ ฉันไม่รู้ว่าทำไม
เดิร์

1
ฉันต้องการ page.onConsoleMessage = function (msg) {};
Andy

5

ฉันพบว่าโซลูชันนี้มีประโยชน์ในแอป NodeJS ฉันใช้ในกรณีที่หมดหวังเพราะมันเปิดตัวหมดเวลาเพื่อรอโหลดหน้าเต็ม

อาร์กิวเมนต์ที่สองคือฟังก์ชันการเรียกกลับซึ่งจะถูกเรียกใช้เมื่อการตอบกลับพร้อม

phantom = require('phantom');

var fullLoad = function(anUrl, callbackDone) {
    phantom.create(function (ph) {
        ph.createPage(function (page) {
            page.open(anUrl, function (status) {
                if (status !== 'success') {
                    console.error("pahtom: error opening " + anUrl, status);
                    ph.exit();
                } else {
                    // timeOut
                    global.setTimeout(function () {
                        page.evaluate(function () {
                            return document.documentElement.innerHTML;
                        }, function (result) {
                            ph.exit(); // EXTREMLY IMPORTANT
                            callbackDone(result); // callback
                        });
                    }, 5000);
                }
            });
        });
    });
}

var callback = function(htmlBody) {
    // do smth with the htmlBody
}

fullLoad('your/url/', callback);

3

นี่คือการดำเนินการตามคำตอบของ Supr นอกจากนี้ยังใช้ setTimeout แทน setInterval ตามที่ Mateusz Charytoniuk แนะนำ

Phantomjs จะออกใน 1000ms เมื่อไม่มีการร้องขอหรือการตอบสนองใด ๆ

// load the module
var webpage = require('webpage');
// get timestamp
function getTimestamp(){
    // or use Date.now()
    return new Date().getTime();
}

var lastTimestamp = getTimestamp();

var page = webpage.create();
page.onResourceRequested = function(request) {
    // update the timestamp when there is a request
    lastTimestamp = getTimestamp();
};
page.onResourceReceived = function(response) {
    // update the timestamp when there is a response
    lastTimestamp = getTimestamp();
};

page.open(html, function(status) {
    if (status !== 'success') {
        // exit if it fails to load the page
        phantom.exit(1);
    }
    else{
        // do something here
    }
});

function checkReadyState() {
    setTimeout(function () {
        var curentTimestamp = getTimestamp();
        if(curentTimestamp-lastTimestamp>1000){
            // exit if there isn't request or response in 1000ms
            phantom.exit();
        }
        else{
            checkReadyState();
        }
    }, 100);
}

checkReadyState();

3

รหัสนี้ฉันใช้:

var system = require('system');
var page = require('webpage').create();

page.open('http://....', function(){
      console.log(page.content);
      var k = 0;

      var loop = setInterval(function(){
          var qrcode = page.evaluate(function(s) {
             return document.querySelector(s).src;
          }, '.qrcode img');

          k++;
          if (qrcode){
             console.log('dataURI:', qrcode);
             clearInterval(loop);
             phantom.exit();
          }

          if (k === 50) phantom.exit(); // 10 sec timeout
      }, 200);
  });

โดยพื้นฐานแล้วคุณควรจะรู้ว่าหน้านั้นถูกดาวน์โหลดแบบเต็มเมื่อองค์ประกอบที่กำหนดปรากฏบน DOM ดังนั้นสคริปต์จะรอจนกว่าจะเกิดเหตุการณ์นี้ขึ้น


3

ฉันใช้การผสมผสานส่วนบุคคลของตัวอย่าง phantomjswaitfor.jsตัวอย่างเช่น

นี่คือmain.jsไฟล์ของฉัน:

'use strict';

var wasSuccessful = phantom.injectJs('./lib/waitFor.js');
var page = require('webpage').create();

page.open('http://foo.com', function(status) {
  if (status === 'success') {
    page.includeJs('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js', function() {
      waitFor(function() {
        return page.evaluate(function() {
          if ('complete' === document.readyState) {
            return true;
          }

          return false;
        });
      }, function() {
        var fooText = page.evaluate(function() {
          return $('#foo').text();
        });

        phantom.exit();
      });
    });
  } else {
    console.log('error');
    phantom.exit(1);
  }
});

และlib/waitFor.jsไฟล์ (ซึ่งเป็นเพียงการคัดลอกและวางของwaifFor()ฟังก์ชันจากwaitfor.jsตัวอย่าง phantomjs ):

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function() {
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if(!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    // console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condi>
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
}

วิธีนี้ไม่ได้เป็นแบบอะซิงโครนัส แต่อย่างน้อยฉันก็มั่นใจได้ว่าทรัพยากรทั้งหมดถูกโหลดก่อนที่จะลองใช้


2

นี่เป็นคำถามเก่า แต่เนื่องจากฉันกำลังมองหาการโหลดแบบเต็มหน้า แต่สำหรับ Spookyjs (ที่ใช้ casperjs และ phantomjs) และไม่พบวิธีการแก้ปัญหาของฉันฉันได้สร้างสคริปต์ของตัวเองด้วยวิธีการเดียวกันกับผู้ใช้ deemstone สิ่งที่วิธีการนี้ทำคือตามระยะเวลาที่กำหนดหากหน้าเว็บไม่ได้รับหรือเริ่มร้องขอใด ๆ ก็จะสิ้นสุดการดำเนินการ

บนไฟล์ casper.js (หากคุณติดตั้งแบบโกลบอลพา ธ จะเป็นสิ่งที่ต้องการ /usr/local/lib/node_modules/casperjs/modules/casper.js) เพิ่มบรรทัดต่อไปนี้:

ที่ด้านบนของไฟล์ที่มี vars ทั้งหมด:

var waitResponseInterval = 500
var reqResInterval = null
var reqResFinished = false
var resetTimeout = function() {}

จากนั้นภายในฟังก์ชั่น "createPage (casper)" หลัง "var หน้า = ต้องการ ('หน้าเว็บ') สร้าง ();" เพิ่มรหัสต่อไปนี้:

 resetTimeout = function() {
     if(reqResInterval)
         clearTimeout(reqResInterval)

     reqResInterval = setTimeout(function(){
         reqResFinished = true
         page.onLoadFinished("success")
     },waitResponseInterval)
 }
 resetTimeout()

จากนั้นภายใน "page.onResourceReceived = ฟังก์ชั่น onResourceReceived (ทรัพยากร) {" ในบรรทัดแรกเพิ่ม:

 resetTimeout()

ทำเช่นเดียวกันกับ "page.onResourceRequested = function onResourceRequested (requestData, request) {"

ในที่สุดใน "page.onLoadFinished = ฟังก์ชั่น onLoadFinished (สถานะ) {" ในบรรทัดแรกเพิ่ม:

 if(!reqResFinished)
 {
      return
 }
 reqResFinished = false

หวังว่าอันนี้จะช่วยคนที่มีปัญหาเหมือนฉัน วิธีนี้ใช้สำหรับ casperjs แต่ใช้ได้กับ Spooky โดยตรง

โชคดี !


0

นี่คือทางออกของฉันมันใช้ได้สำหรับฉัน

page.onConsoleMessage = function(msg, lineNum, sourceId) {

    if(msg=='hey lets take screenshot')
    {
        window.setInterval(function(){      
            try
            {               
                 var sta= page.evaluateJavaScript("function(){ return jQuery.active;}");                     
                 if(sta == 0)
                 {      
                    window.setTimeout(function(){
                        page.render('test.png');
                        clearInterval();
                        phantom.exit();
                    },1000);
                 }
            }
            catch(error)
            {
                console.log(error);
                phantom.exit(1);
            }
       },1000);
    }       
};


page.open(address, function (status) {      
    if (status !== "success") {
        console.log('Unable to load url');
        phantom.exit();
    } else { 
       page.setContent(page.content.replace('</body>','<script>window.onload = function(){console.log(\'hey lets take screenshot\');}</script></body>'), address);
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.