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

时间:2013-06-08 06:23:23

标签: javascript phantomjs

我的目标是使用以下方法执行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

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

3 个答案:

答案 0 :(得分:43)

问题是在第一个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(); ,这可能会导致多个问题。您希望逻辑大致如下(假设文件名作为命令行参数给出):

page.open

是的,它是递归的。这样可以确保在转到下一个文件之前,传递给page = require('webpage').create(); 的函数的处理完成时间为100毫秒。

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

{{1}}

答案 1 :(得分:8)

我已经尝试了接受的答案建议,但它不起作用(至少不适用于v2.1.1)。

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

我找到的最简单的答案是为每个网址实例化一个新的页面模块。

// 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}

     

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

     

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

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

答案 2 :(得分:2)

您可以使用递归:

modelmapper