2012-03-20 44 views
19

我有一个PhantomJS/CasperJS脚本,我使用process.spawn()从node.js脚本运行。由于CasperJS不支持require() ing模块,我试图将命令从CasperJS打印到stdout,然后使用spawn.stdout.on('data', function(data) {});从我的node.js脚本中读取它们,以便将对象添加到redis/mongoose(复杂,是,但似乎比为此设置Web服务更为直接......)CasperJS脚本执行一系列命令并创建20个截图,这些截图需要添加到我的数据库中。解析生成的node.js子进程的输出行

但是,我无法弄清楚如何打破data变量(Buffer?)入行......我试着将其转换为一个字符串,然后做了更换,我试着做spawn.stdout.setEncoding('utf8');,但似乎没有任何工作...

这是我现在所拥有的

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

这是最好的方法吗?看起来'stdout.on('data')'事件根据缓冲区大小触发,不一定是新行。这是真的? – 2012-03-20 04:19:22

回答

14

试试这个:

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

请注意,“数据”事件可能不一定在输出行之间均匀分布,所以单个行可能会跨越多个数据事件。

+0

奇怪的是,我在OSX上 - 我以为“\ r \ n”是Windows。但它似乎工作! (在添加了一些缺失的括号之后:p) – 2012-03-20 04:31:42

+2

@JesseFulton:'\ r'是正则表达式特殊字符'?'的可选项,所以此代码可以在UNIX和Windows上运行;它使正则表达式全局('.../g')在这里可能很关键。在示例代码中调用“替换”使用了一个简单的字符串,该字符串被转换为非全局正则表达式,因此您可能只有两行而不是全部。 – maerics 2012-03-20 05:06:34

+0

啊,你是对的。 String.replace(String,String)不是全局的 - 你需要使用正则表达式作为第一个参数并添加'g'开关。 – 2012-03-20 05:57:00

12

我已经写了一个Node库来达到这个目的,它叫做stream-splitter,你可以在Github上找到它:samcday/stream-splitter

该库提供了一个特殊Stream你可以管你的卡斯帕标准输出入,用分隔符一起(在你的情况,\ n),并且它会发出整齐token事件,每行一个它已经从输入拆分出来Stream。这个内部实现非常简单,并将大部分魔术委托给substack/node-buffers,这意味着没有不必要的Buffer分配/副本。

+0

这个库在这个特殊情况下是一个很棒的节省时间。谢谢! – xShirase 2013-10-18 10:07:51

+0

+1这只是为我工作。麻烦全部消失。谢谢! – 2014-06-01 04:14:54

+0

适用于child_process:var splitter = proc.stdout.pipe(StreamSplitter('\ n')); splitter.on('token',(token)=> {console.log(token)}; //谢谢! – 2016-10-20 05:08:53

1

添加到maerics的答案中,它不能正确处理在数据转储中只输入部分行的情况(他们会单独为您提供行的第一部分和第二部分,作为两个单独的行。)

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

用法:

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

你可以试试这个。它会忽略任何空行或空行换行。

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