批量截图与幻影为nodejs

我拼命试图在一个镜头中处理200个截图,我的第一个尝试是遵循指导,用一个简单的脚本调用200次,

phantom.create() .then(function(instance) { console.log("1 - instance") phInstance = instance; return instance.createPage(); }) .then(function(page) { console.log("2 - page") sitepage = page; return page.open(url); }) .then(function(status) { console.log("3 - render") sitepage.property('clipRect', {top: 0, left: 0, width:3000,height:890}).then(function() { sitepage.render(fname).then(function(finished) { console.log("\t\t\t---> finished"); sitepage.close(); phInstance.exit(); callback({msg: 'ok'}) phantom.exit(); return; }); }); }) 

这个方法有点不错,但是对于cpu来说确实是压倒性的,问题与这样一个事实有关,这种做法导致200个幻影进程快速地消耗掉所有的内存。

一个更有利的方法是创build一个幻像实例,然后驱动它打开一个页面,然后渲染它,这可以用一个幻影脚本完成,如下所示:

  var content, counter, f, fs, grab_screen, img, lines, next_screen, page, system, url; page = require('webpage').create(); system = require('system'); fs = require('fs'); content = ''; lines = []; url = ''; img = ''; counter = 0; page.viewportSize = { width: 1200, height: 800 }; page.settings.userAgent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36'; f = fs.open("sites.txt", "r"); content = f.read(); lines = content.split("\n"); grab_screen = function() { var site; site = lines[counter]; url = 'http://' + site + '/'; img = 'screens/' + site + '.png'; console.log("Grabbing screen for: " + url); return page.open(url, function(status) { return window.setTimeout(function() { page.render(img); counter++; return next_screen(); }, 200); }); }; next_screen = function() { console.log("On to " + counter + " ..."); if (counter < lines.length) { return grab_screen(); } else { return phantom.exit(); } }; next_screen(); 

所以我想知道如何用phantomjs-node实现这一点。

我终于用两件事情解决了我的问题:

  1. 意识到node.js不是multithreading的。
  2. 使用单个幻像实例来呈现多个url。

这是如何出来的:

  var webshot = function(id) { console.log('makeshot ', shots[id].url); requestSync("POST", "http://localhost:4041/options/set", { json:{ opts:JSON.stringify(shots[id].options) } }); phInstance.createPage().then(function(_page) { console.log("2 - page") sitepage = _page; return _page.open(shots[id].url); }) .then(function(status) { console.log("3 - render %s / %s", id, shots.length); sitepage.property('clipRect', {top: 0, left: 0, width:1500,height:220}).then(function() { sitepage.render(shots[id].fname).then(function(finished) { console.log("\t\t\t---> finished"); sitepage.close(); fnames[Math.ceil(parseInt(shots[id].options.pack_id)/mt_per_snap)-1] = "localhost_" + shots[id].options.pack_id + ".png"; if(id<shots.length-1) { id += 1; webshot(id); } else { console.log("all done: %s files has been written", shots.length); // invoke pdf generation for the pdf page cb("files_written", { }); generatePDF(); } return; }); }); }) } 

所以,长话短说:我已经把我想要渲染的页面放在一个单独的脚本中,在拍摄前我用variables提供,这解决了“multithreading问题”,之后我有一个名为phInstance的variables,即声明如下:

  var initPhantom = function() { phantom.create() .then(function(instance) { console.log("1 - instance") phInstance = instance; }) } 

记得一旦完成就杀死幻影实例,否则它 会停留在那里,吸引你的资源。

你可以尝试像webshot东西。 我用它与async.js ,但是我有时得到Error: PhantomJS exited with return value 1 。 还没有find原因。

 async.map( links, function(link, cb) { var config = {...}; // your webshot options var folder = link; // make unique folder name from link? var file = path.join('./', 'screenshots', folder, 'screenshot.png'); webshot(link, file, config, function(err) { cb(err, link); }); }, function(e, links) { // done } ); 

资源:

https://www.npmjs.com/package/webshot https://www.npmjs.com/package/asyncjs