在单个脚本中使用多个page.open

我的目标是通过使用以下命令来执行PhantomJS:

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

然后在script.js ,我打算使用多个page.open()捕获不同页面的屏幕截图,例如:

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

在运行exec ,我在页面上得到以下输出:

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

因此我只能得到第三页的截图。 我不知道为什么PhantomJS跳过了第一个和第二个代码块(显然是从第一个和第二个块输出的console.log()丢失的消息),只执行第三个代码块。

问题是第二个page.open在第一个完成之前被调用,这可能导致多个问题。 你想要的逻辑大致如下(假设文件名是作为命令行参数):

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

对,它是recursion的。 这可以确保传递给page.open的函数的处理完成,只需要100ms的宽限期,然后再转到下一个文件。

顺便说一下,你不需要重复

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

我已经尝试了接受的答案build议,但它不起作用(至less不是v2.1.1)。

为了准确,接受的答案在某些时候起作用,但我仍然经历了零星的失败的page.open()调用,大约90%的时间在特定的数据集上。

我发现最简单的答案是为每个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(){ // ... // ... }) } 

下面从closures方法的页面模块API文档说 :

close(){void}

closures页面并释放与其关联的内存堆。 调用这个之后不要使用页面实例。

由于一些技术限制,网页对象可能没有完全垃圾收集。 当同一个对象反复使用时,经常遇到这种情况。 调用此函数可能会停止增加堆分配。

基本上,在我testing了close()方法后,我决定使用相同的网页实例进行不同的open()调用,这太不可靠了,需要说明的是。

使用排队进程,示例:

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

我希望这是有用的,问候。

你可以使用recursion:

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