5.7 KiB
5.7 KiB
Node 与 Python 处理 Excel 能力对照
针对当前项目(财报 Excel 解析、按配置重组、转亿、多 Sheet 输出),逐项对照:你要实现的功能 Node 是否都支持。
一、当前 Python 用到的能力
| 能力 | 当前实现(Python) | Node 是否支持 | 说明 |
|---|---|---|---|
| 读 .xlsx | pandas + openpyxl | ✅ 支持 | exceljs / xlsx 都支持 |
| 读 .xls | pandas | ⚠️ 部分 | 见下文「.xls」 |
| 读 .csv (UTF-8) | pandas read_csv | ✅ 支持 | fs + 按行解析,或 csv-parse / xlsx 读 csv |
| 按行、按列访问 | df.iloc[i], df.iloc[:, 0] | ✅ 支持 | 工作表 = 二维数组或按行遍历 |
| 按第一列匹配行 | first_col == item_name / str.strip() | ✅ 支持 | 数组 find/filter,字符串 trim |
| 数字解析 | 去 =、逗号、空格,科学计数法 |
✅ 支持 | JS 的 Number/parseFloat 完全够用 |
| 转「亿」、保留 2 位小数 | / 1e8, round(_, 2) | ✅ 支持 | 普通算术 + toFixed/round |
| 多 Sheet 写入 | pd.ExcelWriter, sheet_name= | ✅ 支持 | exceljs 多 worksheet,xlsx 多 sheet |
| 无表头写入 | header=False | ✅ 支持 | 按行写入,不写 header 即可 |
| 按配置过滤行/列 | rows_to_delete, columns_to_keep | ✅ 支持 | 数组 filter / 列索引过滤 |
结论:除「.xls 老格式」需单独处理外,你要实现的功能 Node 都支持。
二、推荐库与用法摘要
1. Excel 读写:exceljs(推荐)
- 读:
workbook.xlsx.readFile(path)→workbook.getWorksheet(1)或按名称 →worksheet.eachRow/row.getCell(j).value - 写:
workbook.addWorksheet('资产负债表')→worksheet.addRow([...]),可多次 addRow 实现「无表头」、多 Sheet - 格式:主要支持 .xlsx;公式会得到计算后的值(与你当前用 pandas 读到的行为一致)
- 中文/UTF-8:无问题
npm i exceljs
2. 备选:xlsx(SheetJS)
- 读:
XLSX.readFile(path)→workbook.Sheets[sheetName]→XLSX.utils.sheet_to_json(sheet, { header: 1 })得到「二维数组」,和你现在按 iloc 按行按列访问等价 - 写:
XLSX.utils.aoa_to_sheet(rows),再XLSX.utils.book_append_sheet(workbook, sheet, '资产负债表'),最后XLSX.writeFile(workbook, path) - 社区版对 .xls 有一定支持(视构建而定);若主要用 .xlsx,exceljs 更易做「按行按格」的细粒度控制
3. CSV
- 用
fs.readFileSync(path, 'utf-8')+ 按行 split + 按逗号/分隔符解析即可 - 或
csv-parse、或直接用 xlsx 读 csv 得到二维数组
4. 数据处理(替代 pandas)
- 不需要 DataFrame:当前脚本本质是「按第一列找行、按列做汇总、按配置过滤、组装新行」
- 用普通数组即可:
rows.find(r => String(r[0]).trim() === itemName)、rows.filter(...)、colValues.reduce((a, b) => a + safeFloat(b), 0)、resultRows.push([...]) - 不需要额外「数据分析」库
三、你关心的几个点
1. 「按第一列找行」在 Node 里怎么写?
和 Python 逻辑一致:把当前 Sheet 读成「行的数组」,每行是「单元格值数组」,用第一列匹配。
// 读成二维数组后
function findRowByItemName(rows, itemName) {
const t = itemName.trim();
return rows.find(r => String(r[0] || '').trim() === t);
}
2. 数字格式:等号、逗号、科学计数法
你现在的 safe_float_convert / convert_to_yi 在 Node 里用一段小函数即可等价实现:
function safeFloat(value) {
if (value == null || value === '') return 0;
let s = String(value).trim();
if (s.startsWith('=')) s = s.slice(1);
s = s.replace(/,|,|\s/g, '');
if (!s || s.toLowerCase() === 'nan') return 0;
const n = parseFloat(s);
return Number.isFinite(n) ? n : 0;
}
科学计数法(如 2.07327E+12)parseFloat 直接支持。
3. 多 Sheet 合并输出(main.py 的 merge_to_excel)
exceljs 示例:
const ExcelJS = require('exceljs');
const wb = new ExcelJS.Workbook();
const ws1 = wb.addWorksheet('资产负债表');
const ws2 = wb.addWorksheet('利润表');
balanceSheetRows.forEach(row => ws1.addRow(row)); // 无表头就连续 addRow
incomeStatementRows.forEach(row => ws2.addRow(row));
await wb.xlsx.writeFile(outputPath);
4. .xls(老格式)
- exceljs:只支持 .xlsx,不直接支持 .xls。
- xlsx (SheetJS):部分版本/配置可读 .xls,但不如 .xlsx 稳定。
- 建议:若数据源仍会提供 .xls,要么在 Node 里用专门库(如
xls等)只做「读成二维数组」再交给现有逻辑,要么在上传前用 Excel/脚本统一转成 .xlsx 再处理。对你当前「下载后上传到 Web」的流程,要求用户上传 .xlsx 或在后端用工具转一次,通常可接受。
四、小结
| 问题 | 结论 |
|---|---|
| Node 能否完成你现在的 Excel 处理? | 能。读 xlsx/csv、按行按列查找、数字清洗、转亿、多 Sheet 写出,都有对应库和写法。 |
| 是否不如 Python 稳? | 对这类场景(报表级数据、几千行以内):Node + exceljs 足够稳;Python 优势在「超大数据、复杂统计、科学计算」,你当前用到的只是基础读写与简单运算。 |
| 推荐方案 | exceljs 做主读写;数据处理用普通 JS 数组;CSV 用 fs + 解析或 csv-parse;.xls 单独处理或要求 .xlsx。 |
你更熟 Node 的话,用 Node 实现当前功能没有问题;若后面遇到具体文件解析异常(例如某个下载站的 xlsx 格式略怪),再针对该格式微调即可。