我是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();
});
有没有办法可以按顺序打开每个链接?
对于这种典型情况,我使用 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
对于这种典型情况,我使用 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
[编辑]
你需要排队这个。我修改了你的代码,并在其中添加了一个简单的队列机制。
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中循环
你可以用 幻象承诺 A PhantomJS bridge with a promise based api.
要么 幻影 PhantomJS integration module for NodeJS
。
按顺序打开每个链接的其他选项
- Cybermaxs 回答
- 使用示例来自 等待 正如Cybermaxs所建议的那样 其他问题
基本上你有3个选择,但你可以采取行动 Casperjs Navigation scripting & testing for PhantomJS and SlimerJS