Como extrair texto de arquivo pdf em NodeJs
Se você chegou até aqui, é por que está com a necessidade de extrair o texto de algum arquivo no formato PDF.
Recentemente eu também passei por isso, revirei a internet em busca da melhor lib
e melhor prática para fazer esse trabalho.
Neste artigo eu vou te mostrar como fiz, quais tecnologias utilizei e práticas.
Criando o projeto NodeJs
Para começar, vamos criar um projeto nodejs simples utilizando um dos comandos abaixo:
yarn init
//ou
npm init
Agora vamos instalar as bibliotecas necessárias que são express e pdfjs-dist:
yarn add express pdfjs-dist
//ou
npm install express pdfjs-dist
Com as libs
instaladas, é hora de criar nosso servidor express.
Já aproveitando, já crie a rota app.get('/file/:filename/:password', async (req, res) => {});
que será utilizada mais para frente.
Crie um arquivo server.js na pasta do seu projeto e crie o servidor como abaixo:
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors());
app.use(express.json());
app.get('/ping', (req, res) => res.send('pong'));
app.get('/file/:filename/:password', async (req, res) => {
// vamos extrair o pdf aqui
res.send('...');
});
app.listen(3333);
module.exports = app;
Classe para extrair o texto do PDF
Agora que já temos o servidor express
criado, vamos criar um arquivo onde iremos escrever o código que irá de fato fazer a extração do texto do arquivo pdf. Aqui eu chamei esse arquivo de readerPDF2Text.js.
Esse arquivo deve ser assim:
const pdfjslib = require('pdfjs-dist/es5/build/pdf')
class Pdf {
static async getPageText (pdf, pageNo) {
const page = await pdf.getPage(pageNo)
const tokenizedText = await page.getTextContent()
const pageText = tokenizedText.items.map(token => token.str).join('')
return pageText
}
static async getPDFText (source, password) {
const pdf = await pdfjslib.getDocument({ data: source, password }).promise
const maxPages = pdf.numPages
const pageTextPromises = []
for (let pageNo = 1; pageNo <= maxPages; pageNo += 1) {
pageTextPromises.push(Pdf.getPageText(pdf, pageNo))
}
const pageTexts = await Promise.all(pageTextPromises)
return pageTexts.join(' ')
}
}
module.exports = Pdf
A biblioteca pdfjslib
é a responsável por fazer o trabalho pesado 😍.
No arquivo server.js
iremos chamar a função getPDFText()
passando o diretório onde o pdf está em nosso servidor e a senha, caso o arquivo esteja protegido por uma.
Este exemplo usa um arquivo pdf que já está salvo em disco no servidor. Caso você precise enviar o arquivo pdf do seu front-end para extrair o texto, sugiro criar uma função para salvar seu arquivo em algum diretório do servidor express e sem seguida usar a função que criamos.
Chamando a função getPDFText
Para finalizar, vamos alterar o arquivo server.js
para chamar a função getPDFText()
e dar o retorno do texto do pdf para o front-end que fizer a requisição na rota /file/:filename/:password
.
const express = require('express');
const Pdf = require('./readerPDF2text')
const fs = require('fs')
const app = express();
const cors = require('cors');
app.use(cors());
app.use(express.json());
app.get('/ping', (req, res) => res.send('pong'));
app.get('/file/:filename/:password', async (req, res) => {
const fileBuffer = fs.readFileSync(req.params.filename);
let pdfRow = null
if (req.params.password){
pdfRow = await Pdf.getPDFText(fileBuffer, req.params.password)
}else {
pdfRow = await Pdf.getPDFText(fileBuffer)
}
res.send(pdfRow);
});
app.listen(3333);
module.exports = app;
Pronto!! Já finalizamos tudo que precisava. Agora basta rodar o servidor express e chamar a rota que criamos para ler o arquivo, passando o diretório e senha.
🟡 Vale lembrar que você não pode chamar sua rota que criamos (com route params) e passar o diretório do arquivo diretamente assim, por exemplo: c:\documents\file.pdf. Esse caminho precisa ser codificado para não gerar erro no servidor. Você pode ler mais sobre isso aqui: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
Concluindo
Vou ficando por aqui espero ter ajudado. 😉
Ficou com alguma dúvida? fique a vontade para me chamar nos comentários!