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

asp*_*rin 24 javascript phantomjs

我的目标是使用以下方法执行PhantomJS:

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

然后在内部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
});
Run Code Online (Sandbox Code Playgroud)

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

Array ( [0] => opening page 3 ) 0
Run Code Online (Sandbox Code Playgroud)

因此,我只获得第3页的屏幕截图.我不确定为什么PhantomJS会跳过第一个和第二个代码块(从console.log()应该从第一个和第二个块输出的丢失消息中显而易见)并且只执行第三个代码块.

小智 44

问题是第二个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();
Run Code Online (Sandbox Code Playgroud)

对,它是递归的.这样可以确保page.open在转到下一个文件之前,传递给函数的处理结束时只有100毫秒的宽限期.

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

page = require('webpage').create();
Run Code Online (Sandbox Code Playgroud)

  • 这不应该是公认的答案 (3认同)

bel*_*nta 8

我已经尝试了接受的答案建议,但它不起作用(至少不适用于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(){
        // ... 
        // ...
    })
}
Run Code Online (Sandbox Code Playgroud)

关于close方法的页面模块api文档中的以下内容如下:

close(){void}

关闭页面并释放与其关联的内存堆.调用后不要使用页面实例.

由于某些技术限制,网页对象可能不会完全被垃圾收集.当一遍又一遍地使用相同的对象时经常会遇到这种情况.调用此函数可能会停止增加堆分配.

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