2013-06-08 14 views
22

Mục tiêu của tôi là để thực hiện PhantomJS bằng cách sử dụng:Sử dụng nhiều page.open trong Độc Script

// adding $op and $er for debugging purposes 
exec('phantomjs script.js', $op, $er); 
print_r($op); 
echo $er; 

Và sau đó bên script.js, tôi có kế hoạch sử dụng nhiều page.open() để chụp ảnh chụp màn hình của trang khác nhau như:

var url = 'some dynamic url goes here'; 
page = require('webpage').create(); 
page.open(url, function (status) { 
    console.log('opening page 1'); 
    page.render('./slide1.png');    
}); 

page = require('webpage').create(); 
page.open(url, function (status) { 
    console.log('opening page 2'); 
    page.render('./slide2.png');   
}); 

page = require('webpage').create(); 
page.open(url, function (status) { 
    console.log('opening page 3'); 
    page.render('./slide3.png');   
    phantom.exit(); //<-- Exiting phantomJS only after opening all 3 pages 
}); 

On chạy exec, tôi nhận được đầu ra sau đây trên trang:

Array ([0] => opening page 3) 0 

Kết quả là tôi chỉ nhận được ảnh chụp màn hình của trang thứ 3. Tôi không chắc tại sao PhantomJS bỏ qua các khối mã đầu tiên và thứ hai (hiển nhiên từ các thông báo thiếu là console.log() được cho là đầu ra từ khối 1 và 2) và chỉ thực thi khối thứ ba của mã.

+0

Tôi tìm thấy https://github.com/ariya/phantomjs/blob/master/examples/render_multi_url.js Nhưng tôi đã tìm cách triển khai nó theo cách đơn giản như cách tôi đang sử dụng hiện tại. – asprin

+0

Có nhưng từ câu hỏi của bạn * nó không thực sự rõ ràng * nơi bạn nhấn roadblock làm điều đó. Bạn về cơ bản chỉ viết rằng "nó không hoạt động" và rằng bạn "nghĩ rằng nó nên làm việc bằng cách nào đó". Đó là khá mô tả. Vì vậy, ngay cả những người có thể biết rằng có thể không có khả năng giải mã câu hỏi của bạn theo cách biết để có câu trả lời cho câu hỏi đó. các ví dụ mã bổ sung thêm ngữ cảnh tốt, nhưng bạn cũng nên xác định chính xác những gì bạn mong đợi để làm việc với ví dụ mã của bạn. – hakre

+0

Cập nhật câu hỏi của tôi với một số thông tin gỡ lỗi – asprin

Trả lời

42

Sự cố là số page.open thứ hai đang được gọi trước khi kết thúc đầu tiên, điều này có thể gây ra nhiều sự cố. Bạn muốn logic gần giống như sau (giả sử tên tệp được đưa ra dưới dạng đối số dòng lệnh):

function handle_page(file){ 
    page.open(file,function(){ 
     ... 
     page.evaluate(function(){ 
      ...do stuff... 
     }); 
     page.render(...); 
     setTimeout(next_page,100); 
    }); 
} 
function next_page(){ 
    var file=args.shift(); 
    if(!file){phantom.exit(0);} 
    handle_page(file); 
} 
next_page(); 

Phải, nó đệ quy. Điều này đảm bảo rằng việc xử lý hàm được chuyển đến page.open kết thúc, với khoảng thời gian gia hạn 100ms nhỏ trước khi bạn chuyển đến tệp tiếp theo.

Bằng cách này, bạn không cần phải tiếp tục lặp đi lặp lại

page = require('webpage').create(); 
+0

Điều đó có ý nghĩa. Hãy để tôi thử nó ra và lấy lại cho bạn về điều này. – asprin

+1

Hữu ích và đơn giản! Cảm ơn bạn! –

+0

Bạn có một nguồn cho thực tế là có nhiều page.open được gọi cùng một lúc gây ra vấn đề cho PhantomJS (hoặc chỉ từ kinh nghiệm)? Tôi đang gặp sự cố liên quan và đang tìm cách giải quyết. – user941238

8

Tôi đã thử những gợi ý trả lời chấp nhận, nhưng nó không hoạt động (ít nhất là không cho v2.1.1).

Để chính xác câu trả lời được chấp nhận đã hoạt động trong một khoảng thời gian, nhưng tôi vẫn gặp phải các cuộc gọi page.open() không thường xuyên, khoảng 90% thời gian trên các tập dữ liệu cụ thể.

Câu trả lời đơn giản nhất tôi tìm được là tạo mô-đun trang mới cho từng url.

// first page 
var urlA = "http://first/url" 
var pageA = require('webpage').create() 

pageA.open(urlA, function(status){ 
    if (status){ 
     setTimeout(openPageB, 100) // open second page call 
    } else{ 
     phantom.exit(1) 
    } 
}) 

// second page 
var urlB = "http://second/url" 
var pageB = require('webpage').create() 

function openPageB(){ 
    pageB.open(urlB, function(){ 
     // ... 
     // ... 
    }) 
} 

The following from the page module api documentation on the close method says:

close() {void}

Đóng trang và giải phóng bộ nhớ heap liên kết với nó. Không sử dụng thể hiện trang sau khi gọi điện thoại này.

Do một số hạn chế về kỹ thuật, đối tượng trang web có thể không được thu gom rác hoàn toàn. Điều này thường gặp phải khi cùng một đối tượng được sử dụng hơn và hơn nữa. Gọi chức năng này có thể dừng phân bổ đống tăng lên.

Về cơ bản sau khi thử nghiệm phương thức close() tôi đã quyết định sử dụng cùng một trang web cho các cuộc gọi open() khác nhau quá đáng tin cậy và cần phải nói.

+0

Đó là 'setTimeout (openPageB(), ...)' dòng không nên có các parens sau khi openPageB. Như là, bạn chỉ cần gọi openPageB ngay tại đó và chuyển giá trị trả về vào setTimeout. – drmercer

+1

drmercer cố định, thx – believesInSanta

1

Bạn có thể sử dụng đệ quy:

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

// the urls to navigate to 
var urls = [ 
    'http://phantomjs.org/', 
    'https://twitter.com/sidanmor', 
    'https://github.com/sidanmor' 
]; 

var i = 0; 

// the recursion function 
var genericCallback = function() { 
    return function (status) { 
     console.log("URL: " + urls[i]); 
     console.log("Status: " + status); 
     // exit if there was a problem with the navigation 
     if (!status || status === 'fail') phantom.exit(); 

     i++; 

     if (status === "success") { 

      //-- YOUR STUFF HERE ---------------------- 
      // do your stuff here... I'm taking a picture of the page 
      page.render('example' + i + '.png'); 
      //----------------------------------------- 

      if (i < urls.length) { 
       // navigate to the next url and the callback is this function (recursion) 
       page.open(urls[i], genericCallback()); 
      } else { 
       // try navigate to the next url (it is undefined because it is the last element) so the callback is exit 
       page.open(urls[i], function() { 
        phantom.exit(); 
       }); 
      } 
     } 
    }; 
}; 

// start from the first url 
page.open(urls[i], genericCallback()); 
+0

cảm ơn bạn, nó hoạt động hoàn hảo với slimerjs –

1

Sử dụng quy trình xếp hàng đợi, mẫu:

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

// Queue Class Helper 
var Queue = function() { 
    this._tasks = []; 
}; 
Queue.prototype.add = function(fn, scope) { 
    this._tasks.push({fn: fn,scope: scope}); 
    return this; 
}; 
Queue.prototype.process = function() { 
    var proxy, self = this; 
    task = this._tasks.shift(); 
    if(!task) {return;} 
    proxy = {end: function() {self.process();}}; 
    task.fn.call(task.scope, proxy); 
    return this;   
}; 
Queue.prototype.clear = function() { 
    this._tasks = []; return this; 
}; 

// Init pages ..... 
var q = new Queue();  

q.add(function(proxy) { 
    page.open(url1, function() { 
    // page.evaluate 
    proxy.end(); 
    });    
}); 

q.add(function(proxy) { 
    page.open(url2, function() { 
    // page.evaluate 
    proxy.end(); 
    });    
}); 


q.add(function(proxy) { 
    page.open(urln, function() { 
    // page.evaluate 
    proxy.end(); 
    });    
}); 

// ..... 

q.add(function(proxy) { 
    phantom.exit() 
    proxy.end(); 
}); 

q.process(); 

Tôi hy vọng điều này là hữu ích, liên quan.