nodejs批量处理pdf,提取关键信息,并导出excel batchPDF
a node programing that fetch key infomation from more than two thousand pdf documents,and output in excel
需求描述:处理同⼀⽬录下的2000个pdf⽂件,提取每个⽂件中的⼀些关键信息(单位名称,统⼀社会信⽤代码,⾏业类别),并整理数据导出为excel表格。
最近在看node⽂件处理,恰好发现校友⾥有个⼟⽊专业的同学提出这么⼀个问题,当时的第⼀想法就是我也许可以做,然后就到了那个同学问清楚了明确需求,并且要了部分pdf⽂件,开始做......  我的第⼀想法就是,⾸先读取⽬录下的⽂件,然后对每个⽂件内容,进⾏正则匹配,出⽬的信息,然后再导出。事实上也是这么回事,基本上分为三步:
1. 读取⽂件
2. 解析⽂件,匹配关键字。
3. 导出excel
读取⽂件
node读取pdf⽂件,引⼊了'pdf2json':
npm install pdf2json --save
复制代码
使⽤这个包,可以将pdf解析为json格式,从⽽得到⽂件的内容
const PDFParser = require('pdf2json');
const src = './pdf';
var pdfParser = new PDFParser(this, 1);
pdfParser.loadPDF(`${src}/${path}`);
<('pdfParser_dataError', errData =>reject( new Error(errData.parserError)));
<('pdfParser_dataReady', () => {
let data = RawTextContent();
});
复制代码
使⽤正则表达式匹配出关键字
⽬标是出每个⽂件中的“单位名称”、”统⼀社会信⽤代码“、“⾏业类别”,仔细分析上⼀过程中输出的结果:
因为要处理的⽂件内容格式都⾮常严谨,我们所要获取的信息都在第三页,解析出的json数据中,⽬标⽂本分布在page(1)和page(3)中,且⽬标⽂本格式都是key:value的格式,每⼀个⽂本都换⾏,所以处理起来就⽅便多了,最终匹配的是以“单位名称:”开头的⼀个或者多个⾮空字符,由于要匹配三个值,所以⽤(red|blue|green)这种⽅式来查⽬标值。
let result = data.match(/(统⼀社会信⽤代码|单位名称|⾏业类别):[\S]*/g);
复制代码
match匹配最终得到⼀个数组:
result = ['统⼀社会信⽤代码:xxx','单位名称:xxx','⾏业类别:xxx']
复制代码
导出为excel表格
⽹上有很多js代码将table导出为excel的代码,这⾥使⽤了'node-xlsx',安装:
npm install node-xlsx --save
复制代码
使⽤这个是因为简单,并且也符合需求,上⼿快。
const xlsx = require('node-xlsx');
var buffer = xlsx.build([{name: 'company', data: list}]);
fs.writeFileSync('list.csv', buffer, 'binary');
复制代码
三⾏代码就搞定了,就得到了⼀个csv格式的excel,剩下的处理就是对list的处理了,传⼊的list需为⼀个⼆维数组,数组的第⼀项为表头,其他项为每⼀⾏对应得数据,也为数组格式。整理的list如下:
[
['序号','统⼀社会信⽤代码','单位名称','⾏业类别'],
['xxx','xxx','xxx','xxxx']
]
复制代码
解析PDF的过程为异步,所以在批量处理⼤量⽂件的情况下,要考虑内存泄漏问题,每次只处理五个,处理完成之后再去处理剩余的⽂件,直到全部完成处理,输出为excel。 当⽂件数量超过30个,报错信息如下:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
复制代码
出现问题的原因:
1. ⽹上有⼀种回答是:解析的是⼀个⼤的⽂件,转换为json后,相当于操作⼀个巨⼤的对象,所以会
报错,但是⽂件数量⼩的时候,解
析是正常的,所以这种假设可以排除。
2. 内存溢出,程序执⾏所需要的内存超出了系统分配给内存⼤⼩
解释:由于node是基于V8引擎,在node中通过javascript使⽤内存时只能使⽤部分内存,64位系统下约为1.4GB,32位系统下约为0.7GB,当执⾏的程序占⽤系统资源过⾼,超出了V8对node默认的内存限制⼤⼩就会报上图所⽰错误。
如果是编译项⽬,V8提供的默认内存⼤⼩不够⽤,可以去修改 --max-old-space-size,但是我⽬前的需求是处理2000多个pdf⽂件,解析为json,所以使⽤的内存⼤⼩是不确定的,不能采取这种⽅案。
我的理解:node js 很多操作都是异步执⾏的,⽽异步操作的结果就是不能确保执⾏完成的时间,所以当多个异步操作同时进⾏的时候,不能确保执⾏完成的顺序,但是执⾏的结果⼜是相互关联的,所以在执⾏的时候,会⼀直占⽤内存,⽽不被垃圾回收机制回收,造成内存泄漏。(也有⼀种可能是队列⾥等待执⾏的任务太多了。。。)
错误的代码
js 二维数组const PDFParser = require('pdf2json');
const fs = require('fs');
const src = './pdf';
const xlsx = require('node-xlsx');
let list = [['序号','统⼀社会信⽤代码','单位名称','⾏业类别']];
let index = 1;
let len = 0;
len = files.length;
files.forEach(item => {
var pdfParser = new PDFParser(this, 1);
pdfParser.loadPDF(`${src}/${item}`);
<('pdfParser_dataError', errData => (errData.parserError)); ('pdfParser_dataReady', () => {
let data = RawTextContent();
let result = data.match(/(统⼀社会信⽤代码|单位名称|⾏业类别):[\S]*/g);
for (let i = 0 ;i < 3;++i){
result[i] = result[i].split(':')[1];
}
list.push(result);
++index;
if( index === len){
var buffer = xlsx.build([{name: 'company', data: list}]); // Returns a buffer
fs.writeFileSync('list.csv', buffer, 'binary');
}
});
});
});
复制代码
但是究竟这个异步操作的并发量的上限是多少,不能确定,有⼀个同学尝试过,读取PDF⽂件的时候,上限是30,分析以上结果,进⾏改进,改进之后,每次执⾏五个异步操作,执⾏完成之后再继续执⾏下⼀个五个异步函数。
测试过,这种⽅式处理100个⽂件时没有问题的,对⽐了两种⽅式⽅法,以34个⽂件为测试⽤例:
⽅法 | ⽂件数量 | 读取时间(s) | CPU | 内存
| :-: |:-: -: | :-: | :-: ⽅法⼀ | 34| 26.817 | 暴涨(14%-42%) | 最⼤(1591MB) ⽅法⼆ | 34| 19.374 | (36%)平稳 | 最⼤(300MB)改进后核⼼代码
ConvertToJSON(path){
return new Promise((resolve,reject) => {
var pdfParser = new PDFParser(this, 1);
pdfParser.loadPDF(`${src}/${path}`);
<('pdfParser_dataError', errData =>reject( new Error(errData.parserError)));        ('pdfParser_dataReady', () => {
// 省略处理部分
resolve(result);
});
}).catch(error => {
console.log(error);
});
}
seek(callback){
let arr = this.files.splice(0,5);
let all = [];
arr.forEach(item => {
all.push(this.ConvertToJSON(item));
});
let promise = Promise.all(all);
promise.then(result => {
// 省略处理部分
return this.files.length === 0 ? callback(this.list) : this.seek(callback);
});
}
复制代码
,欢迎指正。  能够帮助到别⼈同时⾃⼰⼜尝试了新鲜事物,所以觉得很开⼼。
参考⽂档:
1.
2.
3.
4.
5.
6.
7.
在此鸣谢⼤学好友邢旭磊。
我的个⼈博客:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。