【问题标题】:Using Multiple page.open in Single Script在单个脚本中使用多个 page.open
【发布时间】:2017-02-23 05:17:44
【问题描述】:

我的目标是使用以下方法执行 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() 消息中可以看出,应该从第一块和第二块输出)并且只执行第三块代码。

【问题讨论】:

  • 我找到了这个github.com/ariya/phantomjs/blob/master/examples/… 但我希望以一种简单的方式实现它,就像我目前使用的那样。
  • 是的,但从你的问题 这不是很清楚你在哪里遇到了障碍。您基本上只写“它不起作用”并且您“认为它应该以某种方式起作用”。可以说是很形象了。因此,即使是可能知道这一点的人也可能无法以知道有答案的方式解读您的问题。代码示例添加了良好的上下文,但您还应该指出您希望使用代码示例的确切内容。
  • 用一些调试信息更新了我的问题
  • 你有没有仔细检查过三个函数中的前两个都执行了?
  • console.log证明前两个函数没有运行?我还尝试通过注释掉其他两个代码来仅运行第一个代码并且效果很好。

标签: javascript phantomjs


【解决方案1】:

问题是第二个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 的函数的处理完成,并有 100 毫秒的宽限期。

顺便说一句,你不需要一直重复

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

【讨论】:

  • 这是有道理的。让我试一试,然后回复你。
  • 实用又简单!谢谢!
  • 您有一个事实来源,即同时调用多个 page.open 会导致 PhantomJS 出现问题(或仅凭经验)?我遇到了相关问题并正在寻找解决方法。
  • 我来到这个页面是因为我们遇到了类似的问题。奇怪的是,它只是在软件运行后同时打开多达 70 个 url(全部到file://)后才开始发生。所以它绝对有可能并且可以打开多个网址,但是 - 正如我们的情况所证明的那样,它可能存在任意问题。
  • 我在大量页面上尝试过这个并在 ubuntu 上遇到了分段错误。似乎递归调用对内存做了一些讨厌的事情。有没有更可扩展的解决方案?例如。非递归且可水平扩展。
【解决方案2】:

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

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

close() {void}

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

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

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

【讨论】:

  • setTimeout(openPageB(), ...) 行不应该在 openPageB 之后有括号。实际上,您只是在此处调用 openPageB 并将返回值传递给 setTimeout。
【解决方案3】:

你可以使用递归:

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

【讨论】:

    【解决方案4】:

    使用排队进程,示例:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      • 1970-01-01
      • 2015-01-28
      相关资源
      最近更新 更多