代码之家  ›  专栏  ›  技术社区  ›  Necevil

使用Nodejs/Papa Parse解析远程CSV文件?

  •  12
  • Necevil  · 技术社区  · 7 年前

    我目前正在解析来自节点应用程序的远程csv产品提要,并希望使用Papa Parse来完成这项工作(因为我过去在浏览器中成功地使用了Papa Parse)。

    Papa Parse Github: https://github.com/mholt/PapaParse

    我最初的尝试和网络搜索还没有找到具体的方法。Papa自述文件说Papa解析现在与Node兼容,因此Baby Parse(用于提供一些节点解析功能)被贬低了。

    这里有一个指向文档节点部分的链接,供将来遇到此问题的人使用: https://github.com/mholt/PapaParse#papa-parse-for-node

    从doc段落来看,Papa Parse in节点似乎可以解析可读的流,而不是文件。我的问题是;

    是否有任何方法可以利用可读流功能来使用Papa下载/解析节点中的远程CSV?类似于浏览器中的Papa如何使用XMLHttpRequest来实现相同的目标?

    为了将来的可见性 对于那些试图利用此处描述的远程文件解析功能搜索主题(并避免重复类似问题)的用户: http://papaparse.com/docs#remote-files 将在控制台中导致以下错误:

    “未处理的拒绝引用错误:未定义XMLHttpRequest”

    我已经在官方存储库上打开了一个问题,并将在我了解更多需要解决的问题时更新此问题。

    6 回复  |  直到 7 年前
        1
  •  16
  •   David Liao    3 年前

    经过大量的修改,我终于得到了一个使用异步流的工作示例,并且没有额外的库(除了fs/request)。它适用于远程和本地文件。

    我需要创建一个数据流和一个PapaParse流(使用 papa.NODE_STREAM_INPUT 作为 papa.parse() ),然后将数据通过管道传输到PapaParse流中。需要为 data finish 事件 在PapaParse流上 . 然后,您可以在处理程序中使用解析后的数据 完成 事件

    请参见以下示例:

    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的事件碰巧对CSV中的每一行运行一次(尽管我不确定这种行为是否得到保证)。希望这对别人有帮助!

    使用本地文件 除了 dataStream 将使用创建 fs :

    const dataStream = fs.createReadStream("./myfile.csv");
    

    (您可能需要使用 path.join __dirname 指定相对于文件所在位置而不是相对于文件运行位置的路径)

        2
  •  14
  •   TheDuke    7 年前

    好的,我想我有一个答案。但我想只有时间能证明一切。 请注意,我的文件是。带有制表符分隔符的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;
        }
    });
    
        3
  •  11
  •   Michał Karpacki    5 年前

    实际上你可以用 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,也不需要这样做。

        4
  •  1
  •   Community CDub    4 年前

    我正在添加此答案(并将随着我的进度进行更新),以防其他人仍在研究此问题。

    以前的用户似乎都是先下载文件,然后再进行处理。这应该不是必需的,因为Papa Parse应该能够处理读取流,并且应该可以通过管道“http”访问该流。

    下面是一个例子,有人在讨论我正在尝试做什么,然后回到下载文件,然后对其进行解析的过程: https://forums.meteor.com/t/processing-large-csvs-in-meteor-js-with-papaparse/32705/4

    注意:在上面讨论的Baby Parse中,现在Papa Parse与节点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
  •  1
  •   ThomasP1988    5 年前

    Http实际上在回调中有一个可读的流作为参数,因此下面是一个简单的解决方案

     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
  •  0
  •   Алексей Ларионов    4 年前
    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);
      },
    });