2016-04-18 9 views
1

ich dringend etwas wie 200 Screenshots in einem einzigen Schuss bin versucht, zu verarbeiten mein erster Versuch war den Richtlinien mit einem einfachen Skript zu folgen aufgerufen 200mal,Batch Screenshots mit Phantom für NodeJS

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

dieser Ansatz irgendwie funktioniert, aber es ist wirklich überwältigend für die CPU, das Problem ist mit der Tatsache, dass diese Art von Dingen führt zu 200 Phantom-Prozesse, die schnell den ganzen Speicher auffressen verbunden.

Eine rentable Weise, dies zu tun, wäre eine einzige Phantom Instanz zu erstellen und es dann fahren eine Seite zu dem Zeitpunkt zu öffnen und macht es, etwas, das mit einem Phantom Skript getan werden könnte, etwa so:

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

so habe ich mich gefragt, wie man das mit Phantomjs-Knoten erreichen.

Antwort

2

Ich löste schließlich mein Problem mit zwei Dinge:

  1. zu realisieren, dass node.js NICHT Multithreading.
  2. Verwenden einer einzelnen Instanz von Phantom zum Rendern mehrerer URLs.

hier ist, wie es herauskam:

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

so, lange Geschichte kurz: Ich habe die Seite habe ich in einem separaten Skript machen wollte, die ich mit Variablen füttern, bevor der Schuss zu machen und dies löst das "Multi-Threading-Problem", danach habe ich eine einzelne Variable namens phInstance, dass erklärt sich wie folgt:

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

Denken Sie daran, die Phantom-Instanz zu töten, sobald Sie fertig sind, sonst wird es wird dort bleiben und saugen Sie Ihre Ressourcen für immer gut.

0

Sie könnten etwas wie webshot versuchen. Ich verwende es mit async.js, aber manchmal bekomme ich Error: PhantomJS exited with return value 1. Habe noch nicht herausgefunden warum.

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

Ressourcen:

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

+1

Eigentlich habe ich das Problem gelöst, indem ich eine einzige Instanz von Phantom benutzte, um mehrere Anrufe zu tätigen, ich werde eine Antwort schreiben, wie ich das erreicht habe. – holographix

Verwandte Themen