2012-03-20 15 views
19

Ho uno script PhantomJS/CasperJS che sto eseguendo da uno script node.js utilizzando process.spawn(). Dal momento che CasperJS non supporta i moduli require(), sto provando a stampare i comandi da CasperJS a stdout e poi li leggo dal mio script node.js usando spawn.stdout.on('data', function(data) {}); per fare cose come aggiungere oggetti a redis/mangusta (contorto, sì , ma sembra più semplice della creazione di un servizio Web per questo ...) Lo script CasperJS esegue una serie di comandi e crea, diciamo, 20 screenshot che devono essere aggiunti al mio database.Analizzare l'output del processo figlio spa.ed node.js riga per riga

Tuttavia, non riesco a capire come rompere il data variabile (un Buffer?) In linee ... Ho provato a convertirlo in una stringa e poi facendo una sostituzione, ho provato a fare spawn.stdout.setEncoding('utf8'); ma nulla sembra funzionare ...

Ecco quello che ho in questo momento

var spawn = require('child_process').spawn; 

var bin = "casperjs" 
//googlelinks.js is the example given at http://casperjs.org/#quickstart 
var args = ['scripts/googlelinks.js']; 
var cspr = spawn(bin, args); 

//cspr.stdout.setEncoding('utf8'); 
cspr.stdout.on('data', function (data) { 
    var buff = new Buffer(data); 
    console.log("foo: " + buff.toString('utf8')); 
}); 

cspr.stderr.on('data', function (data) { 
    data += ''; 
    console.log(data.replace("\n", "\nstderr: ")); 
}); 

cspr.on('exit', function (code) { 
    console.log('child process exited with code ' + code); 
    process.exit(code); 
}); 

https://gist.github.com/2131204

+1

È questo l'approccio migliore? Sembra che l'evento 'stdout.on ('data')' si attivi a seconda della dimensione del buffer, non necessariamente delle nuove linee. È vero? –

risposta

14

Prova questa:

cspr.stdout.setEncoding('utf8'); 
cspr.stdout.on('data', function(data) { 
    var str = data.toString(), lines = str.split(/(\r?\n)/g); 
    for (var i=0; i<lines.length; i++) { 
    // Process the line, noting it might be incomplete. 
    } 
}); 

Si noti che l'evento "dati" potrebbe non necessariamente rompere uniformemente tra le righe di output, quindi una singola riga potrebbe estendersi su più eventi di dati.

+0

Strano, sono su OSX - Pensavo che "\ r \ n" fosse Windows. Ma sembra funzionare! (dopo aver aggiunto una manciata di parentesi mancanti: p) –

+2

@JesseFulton: il '\ r' è opzionale dal carattere speciale regex'? 'quindi questo codice dovrebbe funzionare sia su UNIX che su Windows; sta rendendo l'espressione regolare globale ('.../g') che probabilmente era critica qui. La chiamata a "sostituire" nel tuo codice di esempio ha usato una semplice stringa che viene convertita in un'espressione regolare non globale, quindi probabilmente hai solo due righe invece di tutte. – maerics

+0

Ah, hai ragione. String.replace (String, String) non è globale: è necessario utilizzare un'espressione regolare come primo parametro e aggiungere l'opzione "g". –

12

Ho effettivamente scritto una libreria di nodi esattamente per questo scopo, si chiama stream-splitter e puoi trovarlo su Github: samcday/stream-splitter.

La libreria fornisce uno speciale Stream è possibile reindirizzare la tua Casper stdout in, insieme a un delimitatore (nel tuo caso, \ n), ed emetterà pulito token eventi, uno per ogni linea che ha spaccato fuori dall'ingresso Stream. L'implementazione interna per questo è molto semplice e delega la maggior parte della magia a substack/node-buffers, il che significa che non ci sono inutili allocazioni/copie Buffer.

+0

Questa libreria è un ottimo risparmio di tempo in questo caso particolare. Grazie! – xShirase

+0

+1 questo ha funzionato solo per me. problemi scomparsi. Grazie! –

+0

Funziona con child_process: var splitter = proc.stdout.pipe (StreamSplitter ('\ n')); splitter.on ('token', (token) => {console.log (token)}; // Grazie! –

1

Aggiunta alla risposta di maerics, che non si adatta in modo appropriato ai casi in cui solo una parte di una riga viene inserita in un dump di dati (la loro porzione ti darà la prima parte e la seconda parte della riga singolarmente, come due righe separate .)

var _breakOffFirstLine = /\r?\n/ 
function filterStdoutDataDumpsToTextLines(callback){ //returns a function that takes chunks of stdin data, aggregates it, and passes lines one by one through to callback, all as soon as it gets them. 
    var acc = '' 
    return function(data){ 
     var splitted = data.toString().split(_breakOffFirstLine) 
     var inTactLines = splitted.slice(0, splitted.length-1) 
     var inTactLines[0] = acc+inTactLines[0] //if there was a partial, unended line in the previous dump, it is completed by the first section. 
     acc = splitted[splitted.length-1] //if there is a partial, unended line in this dump, store it to be completed by the next (we assume there will be a terminating newline at some point. This is, generally, a safe assumption.) 
     for(var i=0; i<inTactLines.length; ++i){ 
      callback(inTactLines[i]) 
     } 
    } 
} 

utilizzo:

process.stdout.on('data', filterStdoutDataDumpsToTextLines(function(line){ 
    //each time this inner function is called, you will be getting a single, complete line of the stdout ^^ 
})) 
0

È possibile dare una prova. Ignorerà tutte le linee vuote o le nuove interruzioni di riga vuote.

cspr.stdout.on('data', (data) => { 
    data = data.toString().split(/(\r?\n)/g); 
    data.forEach((item, index) => { 
     if (data[index] !== '\n' && data[index] !== '') { 
      console.log(data[index]); 
     } 
    }); 
}); 
Problemi correlati