2014-10-09 15 views
16

Phantomjs có hai callbacks thực sự tiện dụng này onLoadStartedonLoadFinished cho phép bạn tạm dừng thực thi trong khi trang đang tải. Nhưng tôi đã tìm kiếm và tôi không thể tìm thấy tương đương nếu bạn click() nút hoặc liên kết gửi. Tải trang tương tự xảy ra nhưng onLoadStarted không được gọi cho sự kiện này tôi đoán vì không xảy ra sự cố rõ ràng page.open(). Tôi đang cố gắng tìm ra một cách rõ ràng để đình chỉ thực hiện trong khi tải này diễn ra.Làm cách nào để đợi sự kiện click() tải trong các bóng ma trước khi tiếp tục?

Một giải pháp rõ ràng là lồng nhau setTimeout nhưng tôi muốn tránh trường hợp này vì nó hacky và dựa vào thử và sai thay vì một cái gì đó đáng tin cậy và mạnh mẽ hơn như thử nghiệm chống lại một cái gì đó hoặc chờ đợi một sự kiện.

Có một cuộc gọi lại cụ thể cho loại tải trang mà tôi đã bỏ lỡ không? Hoặc có thể có một số loại mẫu mã chung có thể giải quyết được vấn đề này?

CHỈNH SỬA:

Tôi vẫn chưa tìm ra cách để tạm dừng. Dưới đây là đoạn code mà không gọi onLoadStarted() chức năng khi tôi gọi là click() lệnh:

var loadInProgress = false; 

page.onLoadStarted = function() { 
    loadInProgress = true; 
    console.log("load started"); 
}; 

page.onLoadFinished = function() { 
    loadInProgress = false; 
    console.log("load finished"); 
}; 

page.open(loginPage.url, function (status) { 
    if (status !== 'success') { 
     console.log('Unable to access network'); 
     fs.write(filePath + errorState, 1, 'w'); 
     phantom.exit(); 
    } else { 
     page.evaluate(function (loginPage, credentials) { 
      console.log('inside loginPage evaluate function...\n') 
      document.querySelector('input[id=' + loginPage.userId + ']').value = credentials.username; 
      document.querySelector('input[id=' + loginPage.passId + ']').value = credentials.password;  
      document.querySelector('input[id=' + loginPage.submitId + ']').click(); 
      //var aTags = document.getElementsByTagName('a') 
      //aTags[1].click(); 
     }, loginPage, credentials); 

     page.render(renderPath + 'postLogin.png'); 
     console.log('rendered post-login'); 

Tôi đôi kiểm tra rằng id là đúng. page.render() sẽ cho biết rằng thông tin được gửi, nhưng chỉ khi tôi đặt nó trong setTimeout(), nếu không nó sẽ hiển thị ngay lập tức và tôi chỉ thấy thông tin đăng nhập được nhập trước khi chuyển hướng trang. Có lẽ tôi đang thiếu cái gì khác?

+0

Bạn chưa thể hiện cách bạn đặt 'onLoadStarted' và' onLoadFinished'. Bạn phải làm điều đó trước khi 'eval' và trình xử lý hoàn tất chứa' render' –

+0

Tôi đã chỉnh sửa nó để bao gồm các định nghĩa gọi lại. Tôi không nghĩ rằng đây là vấn đề mặc dù bởi vì họ không nhận được kêu gọi cho sự kiện 'click()' để bắt đầu. Họ được gọi cho mỗi 'page.open()' mặc dù. –

+0

Có thể bạn 'thoát' quá sớm. Vui lòng xem đoạn cuối cùng trong câu trả lời của tôi. Nó làm việc cho bạn? –

Trả lời

8

Sử dụng trình bao bọc cấp cao, nightmarejs. Bạn có thể dễ dàng click ở đó và đợi sau đó.

Đây là mã (ví dụ mục):

var Nightmare = require('nightmare'); 
new Nightmare() 
    .goto('http://yahoo.com') 
    .type('input[title="Search"]', 'github nightmare') 
    .click('.searchsubmit') 
    .run(function (err, nightmare) { 
     if (err) return console.log(err); 
     console.log('Done!'); 
    }); 

Thêm ví dụ và sử dụng API có thể được tìm thấy tại github

+2

nightmarejs là một mô-đun nút và do đó không áp dụng cho đồng bằng PhantomJS. –

+0

sử dụng thư viện làm cho nó đơn giản hơn nhiều. Cảm ơn đã chỉ ra điều đó! cho nhu cầu của tôi, đó là một lựa chọn tốt hơn –

+0

Wow, giờ đấu tranh với ma, tất cả các vấn đề của tôi được giải quyết trong 5 phút với cơn ác mộng. Thật là một công cụ tuyệt vời, không thể +1 nó đủ. –

12

Tôi nghĩ rằng onLoadStartedonLoadFinished chức năng là tất cả mọi thứ bạn cần. Lấy ví dụ kịch bản sau đây:

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

page.onResourceReceived = function(response) { 
    if (response.stage !== "end") return; 
    console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + response.url); 
}; 
page.onResourceRequested = function(requestData, networkRequest) { 
    console.log('Request (#' + requestData.id + '): ' + requestData.url); 
}; 
page.onUrlChanged = function(targetUrl) { 
    console.log('New URL: ' + targetUrl); 
}; 
page.onLoadFinished = function(status) { 
    console.log('Load Finished: ' + status); 
}; 
page.onLoadStarted = function() { 
    console.log('Load Started'); 
}; 
page.onNavigationRequested = function(url, type, willNavigate, main) { 
    console.log('Trying to navigate to: ' + url); 
}; 

page.open("http://example.com", function(status){ 
    page.evaluate(function(){ 
     // click 
     var e = document.createEvent('MouseEvents'); 
     e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 
     document.querySelector("a").dispatchEvent(e); 
    }); 
    setTimeout(function(){ 
     phantom.exit(); 
    }, 10000); 
}); 

It in

 
Trying to navigate to: http://example.com/ 
Request (#1): http://example.com/ 
Load Started 
New URL: http://example.com/ 
Response (#1, stage "end"): http://example.com/ 
Load Finished: success 
Trying to navigate to: http://www.iana.org/domains/example 
Request (#2): http://www.iana.org/domains/example 
Load Started 
Trying to navigate to: http://www.iana.org/domains/reserved 
Request (#3): http://www.iana.org/domains/reserved 
Response (#2, stage "end"): http://www.iana.org/domains/example 
New URL: http://www.iana.org/domains/reserved 
Request (#4): http://www.iana.org/_css/2013.1/screen.css 
Request (#5): http://www.iana.org/_js/2013.1/jquery.js 
Request (#6): http://www.iana.org/_js/2013.1/iana.js 
Response (#3, stage "end"): http://www.iana.org/domains/reserved 
Response (#6, stage "end"): http://www.iana.org/_js/2013.1/iana.js 
Response (#4, stage "end"): http://www.iana.org/_css/2013.1/screen.css 
Response (#5, stage "end"): http://www.iana.org/_js/2013.1/jquery.js 
Request (#7): http://www.iana.org/_img/2013.1/iana-logo-header.svg 
Request (#8): http://www.iana.org/_img/2013.1/icann-logo.svg 
Response (#8, stage "end"): http://www.iana.org/_img/2013.1/icann-logo.svg 
Response (#7, stage "end"): http://www.iana.org/_img/2013.1/iana-logo-header.svg 
Request (#9): http://www.iana.org/_css/2013.1/print.css 
Response (#9, stage "end"): http://www.iana.org/_css/2013.1/print.css 
Load Finished: success 

Nó cho thấy rằng nhấp chuột vào một liên kết phát ra sự kiện LoadStarted một lần và sự kiện NavigationRequested hai lần, bởi vì có một chuyển hướng. Bí quyết là để thêm xử lý sự kiện trước khi thực hiện hành động:

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

page.open("http://example.com", function(status){ 
    page.onLoadFinished = function(status) { 
     console.log('Load Finished: ' + status); 
     page.render("test37_next_page.png"); 
     phantom.exit(); 
    }; 
    page.onLoadStarted = function() { 
     console.log('Load Started'); 
    }; 

    page.evaluate(function(){ 
     var e = document.createEvent('MouseEvents'); 
     e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 
     document.querySelector("a").dispatchEvent(e); 
    }); 
}); 

Nếu bạn cần phải làm những điều đó, có lẽ đó là thời gian để thử cái gì khác như CasperJS. Nó chạy trên đầu trang của PhantomJS, nhưng có một API tốt hơn để điều hướng các trang web.

0

Đây là mã của tôi dựa trên một số câu trả lời khác. Trong trường hợp của tôi, tôi không cần phải đánh giá cụ thể bất kỳ javascript nào khác. Tôi chỉ cần đợi trang tải xong.

var system = require('system'); 
if (system.args.length === 1) { 
    console.log('Try to pass some arguments when invoking this script!'); 
} 
else { 
    var page = require('webpage').create(); 
    var address = system.args[1]; 

    page.open(address, function(status){ 
     page.onLoadFinished = function(status) { 
      console.log(page.content); 
      phantom.exit(); 
     };  
    });  
} 

Lưu tệp ở trên vào tệp có tên "scrape.js" và gọi nó theo cách này:.

phantomjs --ssl-protocol=any --ignore-ssl-errors=true scrape.js https://www.example.com 

Các params SSL liên quan được bổ sung để tránh các vấn đề khác mà tôi đã có với các trang web HTTPS nhất định (liên quan đến vấn đề giấy chứng nhận tải)

Hy vọng điều này sẽ giúp người

+0

Bạn có chắc chắn mã này hoạt động như bạn mô tả nó không? Hàm gọi lại 'page.open' thực sự nên được gọi cùng lúc với xử lý sự kiện' page.onLoadFinished'. Làm cả hai điều có ý nghĩa với tôi rằng điều thứ hai không bị sa thải. –

+0

@ Artjom-B Có nó hoạt động. Đó là điều tương tự mà bạn đã đăng ngoại trừ việc tôi đã xóa các cuộc gọi page.onLoadStarted và page.evaluate vì tôi không cần chúng. Tôi không chắc tôi hiểu ý bạn là gì. – http203

Các vấn đề liên quan