- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个包含大约 120k HTML 页面的文件夹,我需要打开这些页面(每个文件大约 70kb),使用 xPath 解析一些数据并将该数据附加到 .csv 文件。
下面是我的代码:
它应该从 parseFolder 中读取文件列表,遍历每个文件名,使用 fs.readFile 打开它,然后使用 jsdom 和 xpath 解析数据并使用 fs.appendFile 将其保存到 csv 文件。
前 100 个左右的文件似乎表现不错,但之后会逐渐变慢,消耗内存和 cpu,最终停滞。我有 16 GB 的内存,当我的内存使用量达到大约 7 GB 时,它似乎达到了某个极限。
我是 JS 和 Node 的新手,非常感谢任何指出我遗漏的帮助。
var fs = require('fs');
var jsdom = require('jsdom').jsdom;
var xpath = require('xpath');
var S = require('string');
var os = require('os');
ParserRules = {
saveFile: 'output.csv',
parseFolder: '/a/folder/with/120k/HTML/files',
fields: {
"field1": "//div[@class='field1']/text()",
}
};
start();
function start() {
console.log('Starting...');
fs.readdir(ParserRules.parseFolder, iterateFiles);
}
function iterateFiles(err, filesToParse) {
for (var i = 0; i < filesToParse.length; i++) {
file = ParserRules.parseFolder + '/' + filesToParse[i];
console.log('Beginning read of ' + file);
fs.readFile(file, {encoding: 'utf8'}, parseFile);
}
}
function parseFile(err, data) {
if (err == null) {
var jsdomDocument = jsdom(data);
var document = jsdomDocument.parentWindow.document;
getContent(document);
}
}
function getContent(document) {
fields = ParserRules.fields;
var csvRow = [];
for (var field in fields) {
try {
console.log('Looking for ' + field);
var nodes = xpath.select(fields[field], document);
for (var i = 0; i < nodes.length; i++) {
csvRow.push(getValue(nodes[i]));
}
} catch (err) {
console.log(err);
}
}
saveToCsv(csvRow, ParserRules.saveFile);
}
function getValue(node) {
if(node.nodeValue != null) {
toReturn = node.nodeValue;
} else {
newNode = $(node);
toReturn = newNode.html();
}
return toReturn;
}
function saveToCsv(object, filePath) {
console.log('Saving...');
if(object.length > 0) {
console.log('Row Exists, Saving...');
toString = S(object).toCSV().s + os.EOL;
fs.appendFile(filePath, toString, {encoding: 'utf8', flag: 'a'}, function(err){
if (err) {
console.log('Write Error: ' + err);
} else {
console.log('Saved ' + object);
}
});
}
}
最佳答案
Node.js 异步工作。
因此您的代码结构方式会发生这种情况:
iterateFiles
函数连续发出 120k 次 fs.readFile
调用,这导致 Node.js 将 120k 文件系统读取操作排队。
当读取操作完成时,Node.js 将为 fs.readFile
调用 120k 回调,并且每个回调都会发出一个 fs.appendFile
操作,这将导致 Node.js 排队 120k 文件系统写入操作。
最终 Node.js 将调用传递给 fs.appendFile
的 120k 回调。在这些写入操作完成之前,Node.js 必须挂起要写入的数据。
对于这样的任务,我建议使用 fs 调用的同步版本:fs.readFileSync
和 fs.appendFileSync
。
在为 Web 服务器或以某种方式由事件驱动编写代码时,您不希望使用这些调用的同步版本,因为它们会导致您的应用程序阻塞。但是,如果您正在编写对数据进行批处理的代码(例如,像 shell 脚本一样运行的代码),则使用这些调用的同步版本会更简单。
以下代码是您的代码的简化模型并说明了问题。它被设置为从 /tmp
中读取,因为它与任何文件源一样好。如果文件为空,我还将其设置为避免做任何比 parseFile
更进一步的工作。
var fs = require('fs');
var ParserRules = {
saveFile: 'output.csv',
parseFolder: '/tmp'
};
start();
function start() {
console.log('Starting...');
fs.readdir(ParserRules.parseFolder, iterateFiles);
}
function iterateFiles(err, filesToParse) {
for (var i = 0; i < filesToParse.length; i++) {
var file = ParserRules.parseFolder + '/' + filesToParse[i];
console.log('Beginning read of file number ' + i);
fs.readFile(file, {encoding: 'utf8'}, parseFile);
}
}
var parse_count = 0;
function parseFile(err, data) {
if (err)
return;
if (data.length) {
console.log("Parse: " + parse_count++);
getContent(data);
}
}
function getContent(data) {
saveToCsv(data, ParserRules.saveFile);
}
var save_count = 0;
function saveToCsv(data, filePath) {
fs.appendFile(filePath, data, {encoding: 'utf8', flag: 'a'},
function(err){
if (err) {
console.log('Write Error: ' + err);
} else {
console.log('Saved: ' + save_count++);
}
});
}
如果运行此代码,您会看到所有 Parse:
消息连续出现。然后仅在所有Parse:
消息输出后,您会得到Saved:
消息。所以你会看到类似的东西:
Beginning read of file number N
Beginning read of file number N+1
Parse: 0
Parse: 1
... more parse messages ...
Parse: 18
Parse: 19
Saved: 0
Saved: 1
... more saved messages...
Saved: 18
Saved: 19
这告诉你的是,在解析完所有文件之前,Node 不会开始保存。由于 Node 无法释放与文件关联的数据,直到它知道不会再次使用它---在这种情况下,这意味着直到文件被保存---然后在某个时候 Node 将至少占用 120,000 * 70kb 内存用于保存所有文件中的所有数据。
关于javascript - 为什么我的 NodeJS 脚本在 fs.readFile 和 fs.appendFile 处理大量文件时陷入困境。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21583968/
我是 JavaFx 新手,正在尝试编写我的刽子手游戏。我现在必须检查保存我的词典的文件是否在那里。如果没有,请用户输入其位置。我试图在弹出窗口中执行此操作,要求用户输入位置并点击按钮,该按钮反过来将导
我卡住了。我试图用 SQLite 表的字段填充 ListView 。我对 Android 编程很陌生。关于我为什么会收到此错误的任何建议: 10-24 10:24:31.154: ERROR/Andr
我正在编写一个 java 程序,它接受用户输入的数字 x,对从 1 到 x(包括 x)的所有可被 3 整除的数字求和,并显示总和。它编译没有错误但是当我执行程序时,它陷入循环并继续执行直到我关闭命令提
JS 和 Web 编程新手。 我有一个图像在 Canvas 上沿水平轴移动。当图像到达某个点时,我希望它停止、缩放然后旋转。我使用的方法会导致无限循环,我不明白为什么。 这是被调用的方法 while
我制作了一个使用表单、php 和 javascript 进行登录和注销的页面。 但唯一的问题是,当您提交表单并且数据发生更改时,直到页面重新加载后才会更新。 注意lo
我在查询时陷入困境。我想根据“时间和点赞数”查询帖子,但不知道如何在 firebase 上查询。示例: Query mquery =FireBaseDatabase() getReference().
这个问题已经有答案了: Why does my ArrayList contain N copies of the last item added to the list? (5 个回答) 已关闭 6
所以,我有一个项目,任务是这样表述的: 您需要创建一个名为 Candidate 的类,它存储参加选举的人的姓氏以及他们获得的票数。您还应该有访问每个字段的方法。此时,这些字段不需要修改器,因为它们不应
我正在解决 Java 编程类(class)中的作业问题,但我陷入了困境。我会预先告诉你,我绝不是专家,并且对 Java 或一般编程了解不多。 我遇到的问题实际上不是我的作业问题,而是书中的一个例子,我
我正在用java编写一个客户端程序。服务器是用C++编写的。当我从以下位置发送消息时客户端到服务器就可以了。但是在接收过程中我的客户端线程陷入了这个调用 in = new BufferedReader
我正在参加 Edx 上的在线类(class) cs50,我有一个作业,其中我必须创建一个程序,用户在其中输入关键字(然后用于加密)和需要在 Vigenere 中加密的字符串。密码。 Vigenere
我遇到了陷入 getIntLimited 函数的问题。在调整数量中,我需要它检查用户是否输入了正确的数字,而不是多于或少于所需的数字,而不是字母。我没有对“库存”选项这样做,只在“检查”选项中这样做。
我更喜欢创建一个 Dictionary 对象并向其中添加 3 个单词。我的程序没有编译错误,但在第二个 for 循环中出现运行时错误,问题出在 addNewWord 函数中吗?我需要传递一个指向 Di
该程序的要点是获取 2 个文件,一个是字典,另一个是文本,创建一个输出文件,并将文本文件中的所有单词放入其中,但将文本文件中不存在的单词大写字典。 当我运行程序时,它不断要求输入,所以看起来我陷入了
我正在为我的 C++ 类(class)做作业。在这个作业中,我需要编写一个程序,从 cin 中读取数字,然后对它们求和,当使用 while 循环输入 0 时停止。 我已经编写了代码并获得了我需要的结果
这是我到目前为止所得到的- $awards_sql_1 = mysql_query('SELECT * FROM categories WHERE section_id = 1') or die(my
我想弄清楚某个步骤何时发生。所以我编写了一个名为 countSteps 的方法来执行此操作。它的问题是我陷入其中,因为在 while 循环中我不断获取新数据,而且我认为它永远不会返回到 onSenso
我有点卡在一个问题上了。我有一个 Spring + Hibernate 应用程序,最近几天表现得很奇怪。 通常,即使在 Debug模式下,它也会引导大约 15 秒。 几天后,在没有显示任何重大错误或问
我是编程新手,我想知道是否有人可以帮助我解决这个问题?它似乎处于连续循环中,我一直在更改它并尝试不同的方法近一个小时,将不胜感激。 #include "stdafx.h" #include
我正在用 Python 创建一个聊天服务器,并且对这门语言的了解还很浅。我现在有 1 个问题,我想在进一步解决之前解决,但我似乎找不到解决问题的方法。 这是一个持续的 while 循环.. 下面的代码
我是一名优秀的程序员,十分优秀!