2012-03-20 31 views
19

Mam skrypt PhantomJS/CasperJS, który uruchamiam z poziomu skryptu node.js, używając process.spawn(). Ponieważ CasperJS nie obsługuje modułów require(), próbuję wydrukować polecenia od CasperJS do stdout, a następnie wczytać je ze skryptu node.js za pomocą spawn.stdout.on('data', function(data) {});, aby dodać obiekty do redis/mangusta (zawiłe, tak , ale wydaje się prostsze niż ustawienie usługi internetowej dla tego ...) Skrypt CasperJS wykonuje serię poleceń i tworzy, powiedzmy, 20 zrzutów ekranu, które należy dodać do mojej bazy danych.Dane wyjściowe sparsowanego potomnego wiersza procesowego node.js według wiersza

Jednak nie mogę dowiedzieć się, jak przełamać data zmiennej (a Buffer?) Na linii ... Próbowałem przekształcenie go na sznurku, a potem robi zastąpić, próbowałem robić spawn.stdout.setEncoding('utf8'); ale nic nie wydaje się działać ...

Oto co mam teraz

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

Czy to najlepsze podejście? Wygląda na to, że zdarzenie 'stdout.on ('data')' uruchamia się w zależności od rozmiaru bufora, niekoniecznie nowych linii. Czy to prawda? –

Odpowiedz

14

Spróbuj tego:

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

Należy zauważyć, że zdarzenie "data" niekoniecznie musi przebiegać równomiernie między wierszami danych wyjściowych, więc pojedynczy wiersz może obejmować wiele zdarzeń danych.

+0

Dziwne, jestem na OSX - myślałem, że "\ r \ n" było Windows. Ale wydaje się działać! (po dodaniu garstki brakujących nawiasów: p) –

+2

@JesseFulton: '\ r' jest opcjonalne ze specjalnego znaku wyrażeń regularnych'? ', więc ten kod powinien działać zarówno w systemie UNIX, jak i Windows; to sprawia, że ​​wyrażenie regularne globalne ('.../g') było prawdopodobnie tutaj krytyczne. Wywołanie "zastąpić" w przykładowym kodzie użyło zwykłego łańcucha, który zostanie przekonwertowany na niegeometryczne wyrażenie regularne, więc prawdopodobnie masz tylko dwa wiersze zamiast wszystkich. – maerics

+0

Ach, masz rację. String.replace (String, String) nie jest globalny - musisz użyć wyrażenia regularnego jako pierwszego parametru i dodać przełącznik "g". –

12

ja faktycznie napisane biblioteki węzła dokładnie ten cel, to się nazywa strumień-splitter i można go znaleźć na Github: samcday/stream-splitter.

Biblioteka zapewnia specjalny Stream można rura Twój Casper stdout się wraz z ogranicznikiem (w przypadku, \ n), i będzie emitować schludne token zdarzenia, po jednym dla każdej linii ona podzieliła się z wejścia Stream. Wewnętrzna implementacja jest bardzo prosta i przekazuje większość magii na substack/node-buffers, co oznacza, że ​​nie ma niepotrzebnych przydziałów/kopii Buffer.

+0

Ta biblioteka świetnie się sprawdza w tym konkretnym przypadku. Dzięki! – xShirase

+0

+1 to właśnie dla mnie zadziałało. kłopoty zniknęły. Dzięki! –

+0

Działa z child_process: var splitter = proc.stdout.pipe (StreamSplitter ('\ n')); splitter.on ('token', (token) => {console.log (token)}; // Thanks! –

1

Dodawanie do odpowiedzi maerii, która nie radzi sobie właściwie z przypadkami, w których tylko część linii jest podawana w zrzucie danych (ich pierwsza część i druga część linii będą osobno, jako dwie oddzielne linie .)

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

wykorzystanie:

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

Możesz dać to spróbować. Zignoruje wszystkie puste linie lub puste nowe podziały wierszy.

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]); 
     } 
    }); 
}); 
Powiązane problemy