使用 Nodejs / Papa Parse 解析远程 CSV 文件?
Posted
技术标签:
【中文标题】使用 Nodejs / Papa Parse 解析远程 CSV 文件?【英文标题】:Parse Remote CSV File using Nodejs / Papa Parse? 【发布时间】:2018-05-29 03:06:17 【问题描述】:我目前正在从 Node 应用程序解析远程 csv 产品提要,并希望使用 Papa Parse 来执行此操作(因为我过去曾在浏览器中成功使用它)。
Papa Parse Github:https://github.com/mholt/PapaParse
我最初的尝试和网络搜索并没有确切地表明这将如何完成。 Papa 自述文件说 Papa Parse 现在与 Node 兼容,因此 Baby Parse(用于提供某些 Node 解析功能)已被贬低。
这里是文档中节点部分的链接,供将来遇到此问题的任何人参考:https://github.com/mholt/PapaParse#papa-parse-for-node
从该文档段落看来,Node 中的 Papa Parse 可以解析可读流而不是文件。我的问题是;
有什么方法可以利用 Readable Streams 功能来使用 Papa 在 Node 中下载/解析远程 CSV,这与 Papa 在浏览器中使用 XMLHttpRequest 实现相同目标的方式类似吗?
为了未来的可见性 对于那些尝试使用此处描述的远程文件解析功能的主题搜索(并避免重复类似问题)的人:http://papaparse.com/docs#remote-files 将在您的控制台中导致以下错误:
“未处理的拒绝 ReferenceError:未定义 XMLHttpRequest”
我已经在官方存储库上打开了一个问题,并将在我了解更多关于需要解决的问题时更新这个问题。
【问题讨论】:
【参考方案1】:好的,所以我想我有一个答案。但我想只有时间会证明一切。 请注意,我的文件是带有制表符分隔符的 .txt。
var fs = require('fs');
var Papa = require('papaparse');
var file = './rawData/myfile.txt';
// When the file is a local file when need to convert to a file Obj.
// This step may not be necissary when uploading via UI
var content = fs.readFileSync(file, "utf8");
var rows;
Papa.parse(content,
header: false,
delimiter: "\t",
complete: function(results)
//console.log("Finished:", results.data);
rows = results.data;
);
【讨论】:
【参考方案2】:经过大量修改后,我终于得到了一个使用异步流且没有其他库(fs/request 除外)的工作示例。它适用于远程和本地文件。
我需要创建一个数据流和一个 PapaParse 流(使用papa.NODE_STREAM_INPUT
作为papa.parse()
的第一个参数),然后将数据通过管道传输到 PapaParse 流中。 PapaParse 流上的data
和finish
事件需要实现事件侦听器。然后,您可以将处理程序中的解析数据用于finish
事件。
请看下面的例子:
const papa = require("papaparse");
const request = require("request");
const options = /* options */;
const dataStream = request.get("https://example.com/myfile.csv");
const parseStream = papa.parse(papa.NODE_STREAM_INPUT, options);
dataStream.pipe(parseStream);
let data = [];
parseStream.on("data", chunk =>
data.push(chunk);
);
parseStream.on("finish", () =>
console.log(data);
console.log(data.length);
);
parseStream 的 data
事件恰好为 CSV 中的每一行运行一次(尽管我不确定这种行为是否得到保证)。希望这对某人有帮助!
要使用本地文件而不是远程文件,您可以执行相同的操作,但 dataStream
将使用 fs
创建:
const dataStream = fs.createReadStream("./myfile.csv");
(您可能希望使用path.join
和__dirname
指定相对于文件所在位置的路径,而不是相对于运行位置的路径)
【讨论】:
大卫如果这可行(还没有尝试过)它应该是接受的答案!干得好! 这应该是公认的答案,因为它实际上用 papa parse 回答了远程和本地文件的问题 最佳答案【参考方案3】:实际上,您可以使用lightweight stream transformation library called scramjet - 直接从 http 流解析 CSV 是我的主要示例之一。它还使用PapaParse 解析CSV。
您在上面写的所有内容,以及介于两者之间的任何转换,都可以在几行内完成:
const StringStream = require("scramjet");
const request = require("request");
request.get("https://srv.example.com/main.csv") // fetch csv
.pipe(new StringStream()) // pass to stream
.CSVParse() // parse into objects
.consume(object => console.log("Row:", object)) // do whatever you like with the objects
.then(() => console.log("all done"))
在您自己的示例中,您将文件保存到磁盘,即使使用 PapaParse 也没有必要。
【讨论】:
很高兴听到这个消息。 :) .pipe(new StringStream) 当我使用它时,我会得到下面的错误:[ts] 不能将“new”与类型缺少调用或构造签名的表达式一起使用。 在后面加上括号:new StringStream()
.
.csvParse() 方法从何而来?
@SamSverko 现在我注意到了 - 确实是 CSVParse
- 我会在上面更正这个问题。【参考方案4】:
我正在添加这个答案(并会随着我的进展更新它)以防其他人仍在调查这个问题。
似乎以前的用户最终会先下载文件然后再处理它。这不应该是必要的,因为 Papa Parse 应该能够处理读取流,并且应该可以通过管道将“http”GET 传输到该流。
这是一个例子,有人在讨论我正在尝试做的事情并返回下载文件然后解析它:https://forums.meteor.com/t/processing-large-csvs-in-meteor-js-with-papaparse/32705/4
注意:在上面讨论了 Baby Parse,现在 Papa Parse 与 Node Baby Parse 一起工作已经被贬低了。
下载文件解决方法
虽然下载然后使用 Papa Parse 进行解析不能回答我的问题,但这是我目前唯一的解决方法,其他人可能想要使用这种方法。
我要下载然后解析的代码目前看起来像这样:
// Papa Parse for parsing CSV Files
var Papa = require('papaparse');
// HTTP and FS to enable Papa parse to download remote CSVs via node streams.
var http = require('http');
var fs = require('fs');
var destinationFile = "yourdestination.csv";
var download = function(url, dest, cb)
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response)
response.pipe(file);
file.on('finish', function()
file.close(cb); // close() is async, call cb after close completes.
);
).on('error', function(err) // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
);
;
download(feedURL, destinationFile, parseMe);
var parseMe = Papa.parse(destinationFile,
header: true,
dynamicTyping: true,
step: function(row)
console.log("Row:", row.data);
,
complete: function()
console.log("All done!");
);
【讨论】:
【参考方案5】:Http(s)实际上在回调中有一个可读流作为参数,所以这里有一个简单的解决方案
try
var streamHttp = await new Promise((resolve, reject) =>
https.get("https://example.com/yourcsv.csv", (res) =>
resolve(res);
)
);
catch (e)
console.log(e);
Papa.parse(streamHttp, config);
【讨论】:
【参考方案6】:const Papa = require("papaparse");
const StringStream = require("scramjet");
const request = require("request");
const req = request
.get("https://example.com/yourcsv.csv")
.pipe(new StringStream());
Papa.parse(req,
header: true,
complete: (result) =>
console.log(result);
,
);
【讨论】:
恭喜您发布了您的第一个答案!最好提供一些背景信息或指导说明您的答案为何适合该问题。以上是关于使用 Nodejs / Papa Parse 解析远程 CSV 文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Papa Parse 从 CSV 文件中提取数据到 React 状态?
NodeJs JSON.parse-SyntaxError:JSON中位置0处的意外令牌u