问题 PhantomJS的承诺框架?


我是PhantomJS的新手。我想加载一个页面,抓取它的链接,然后按顺序打开每个页面,一次打开一个,甚至可能在每个请求之间有一个延迟。我很难找到另一个,所以我想也许我可以使用promises来解决这个问题,但我不认为Node库可以与Phantom一起工作。到目前为止,我见过的每个例子都会打开一个页面,然后退出。

这是我得到的:

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

page.open('http://example.com/secretpage', function(status) {
    console.log(status);
    if(status !== 'success') {
        console.log('Unable to access network');
    } else {
        var links = page.evaluate(function() {
            var nodes = [];
            var matches = document.querySelectorAll('.profile > a');
            for(var i = 0; i < matches.length; ++i) {
                nodes.push(matches[i].href);
            }
            return nodes;
        });


        links.forEach(function(link) {
            console.log(link);
            page.open(link, function(status) { // <---- tries opening every page at once
                console.log(status);

                var name = page.evaluate(function() {
                    return document.getElementById('username').innerHTML;
                });

                console.log(name);
                page.render('profiles/'+name + '.png');
            });
        });
    }
//    phantom.exit();
});

有没有办法可以按顺序打开每个链接?


8650
2018-02-25 04:34


起源



答案:


对于这种典型情况,我使用 async.js 尤其是队列 零件

这是一个非常基本的实现

phantom.injectJs('async.js');

var q = async.queue(function (task, callback) {
    page.open(task.url, function(status) { // <---- tries opening every page at once
                if(status !== 'success') {
        console.log('Unable to open url > '+task.url);
    } else {
                console.log('opened '+task.url);
                //do whatever you want here ...
                    page.render(Date.now() + '.png');
                }           
                callback();
            });

}, 1);

// assign a callback
q.drain = function() {
    console.log('all urls have been processed');
    phantom.exit();
}

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

page.open('http://phantomjs.org/', function(status) {
    console.log(status);
    if(status !== 'success') {
        console.log('Unable to access network');
    } else {
        var links = page.evaluate(function() {
            var nodes = [];
            var matches = document.querySelectorAll('a');
            for(var i = 0; i < matches.length; ++i) {
                nodes.push(matches[i].href);
            }
            return nodes;
        });

        links.forEach(function(link) {
                q.push({url: link}, function (err) {
                    console.log('finished processing '+link);
                });
        });
    }   
});

Urls被添加到队列中并将被并行处理(最多达到并发限制,此处为1)。我重用了相同的页面实例,但这不是强制性的。

由于我过去已经使用过这种爬虫,让我再给你两个建议:

  • 不要加载图像以加快测试速度
  • href有时是相对的,所以首先检查它是否是有效的URL

4
2018-02-25 07:31



当我尝试做phantom.injectJs('async.js')时,我收到一个错误:ReferenceError:找不到变量:exports ....与在async.js中实现AMD的方式有关? phantomjs 1.9.8和phantomjs 2都会发生这种情况 - J. Barca


答案:


对于这种典型情况,我使用 async.js 尤其是队列 零件

这是一个非常基本的实现

phantom.injectJs('async.js');

var q = async.queue(function (task, callback) {
    page.open(task.url, function(status) { // <---- tries opening every page at once
                if(status !== 'success') {
        console.log('Unable to open url > '+task.url);
    } else {
                console.log('opened '+task.url);
                //do whatever you want here ...
                    page.render(Date.now() + '.png');
                }           
                callback();
            });

}, 1);

// assign a callback
q.drain = function() {
    console.log('all urls have been processed');
    phantom.exit();
}

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

page.open('http://phantomjs.org/', function(status) {
    console.log(status);
    if(status !== 'success') {
        console.log('Unable to access network');
    } else {
        var links = page.evaluate(function() {
            var nodes = [];
            var matches = document.querySelectorAll('a');
            for(var i = 0; i < matches.length; ++i) {
                nodes.push(matches[i].href);
            }
            return nodes;
        });

        links.forEach(function(link) {
                q.push({url: link}, function (err) {
                    console.log('finished processing '+link);
                });
        });
    }   
});

Urls被添加到队列中并将被并行处理(最多达到并发限制,此处为1)。我重用了相同的页面实例,但这不是强制性的。

由于我过去已经使用过这种爬虫,让我再给你两个建议:

  • 不要加载图像以加快测试速度
  • href有时是相对的,所以首先检查它是否是有效的URL

4
2018-02-25 07:31



当我尝试做phantom.injectJs('async.js')时,我收到一个错误:ReferenceError:找不到变量:exports ....与在async.js中实现AMD的方式有关? phantomjs 1.9.8和phantomjs 2都会发生这种情况 - J. Barca


[编辑]

你需要排队这个。我修改了你的代码,并在其中添加了一个简单的队列机制。

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

page.open('http://example.com/secretpage', function(status) {
    console.log(status);
    if (status !== 'success') {
        console.log('Unable to access network');
    } else {
        var links = page.evaluate(function() {
            var nodes = [];
            var matches = document.querySelectorAll('.profile > a');
            for (var i = 0; i < matches.length; ++i) {
                nodes.push(matches[i].href);
            }
            return nodes;
        });

        var pointer = 0,
            linksCount = links.length,
            q = function() {
                var link = links[pointer];
                console.log(link);

                page.open(link, function(status) { // <---- tries opening every page at once
                    console.log(status);

                    var name = page.evaluate(function() {
                        return document.getElementById('username').innerHTML;
                    });

                    console.log(name);
                    page.render('profiles/' + name + '.png');

                    // pointer increaments;
                    pointer++;
                    if (pointer == linksCount) {
                        // recursion exit
                        phantom.exit();
                    }
                    else {
                        // recursive cal;
                        q();
                    }
                });             

            };

        // start queue to load links one by one     
        q();
});

注意:foreach不会等待每个页面加载,页面加载是异步的。因此你的问题。

您可以在CasperJS(PhantomJS的包装器)上阅读类似问题的答案,其中包含如何处理此问题的代码 如何在casperjs中循环


4
2018-02-26 07:50



使用时 async.js 正如Cyber​​maxs所回答的那样 - 我承认,Betclic绝对是完美和美好的。 - sudipto


你可以用 幻象承诺  A PhantomJS bridge with a promise based api. 要么 幻影  PhantomJS integration module for NodeJS。 按顺序打开每个链接的其他选项

  1. Cyber​​maxs 回答
  2. 使用示例来自 等待 正如Cyber​​maxs所建议的那样 其他问题

基本上你有3个选择,但你可以采取行动 Casperjs  Navigation scripting & testing for PhantomJS and SlimerJS


2
2017-09-21 14:06