2009-10-12 84 views
22

Me pregunto si es posible obtener el texto dentro de un archivo PDF usando solo Javascript? En caso afirmativo, ¿alguien me puede mostrar cómo?extraer texto del pdf en Javascript

Sé que hay algunas bibliotecas del lado del servidor java, C#, etc. pero preferiría no usar un servidor. gracias

Respuesta

46

Esta es una antigua cuestión, pero debido a que pdf.js se ha desarrollado a lo largo de los años, me gustaría dar una nueva respuesta. Es decir, se puede hacer localmente sin involucrar ningún servidor o servicio externo. El nuevo pdf.js tiene una función: page.getTextContent(). Puedes obtener el contenido de texto de eso. Lo he hecho con éxito con el siguiente código.

  1. Lo que obtienes en cada paso es una promesa. Debe codificar de esta manera: .then(function(){...}) para pasar al siguiente paso.

    1) PDFJS.getDocument(data).then(function(pdf) {

    2) pdf.getPage(i).then(function(page){

    3) page.getTextContent().then(function(textContent){

  2. Lo que finalmente se obtiene es una matriz de cadenas textContent.bidiTexts[]. Los concatenas para obtener el texto de 1 página. Las coordenadas de los bloques de texto se utilizan para juzgar si se debe insertar nueva línea o espacio. (Esto puede no ser totalmente robusto, pero de mi prueba parece estar bien.)

  3. El parámetro de entrada data debe ser un tipo de datos de URL o ArrayBuffer. Usé la función ReadAsArrayBuffer (archivo) en FileReader API para obtener los datos.

Espero que esto ayude.

Nota: De acuerdo con algún otro usuario, la biblioteca se ha actualizado y provocó la ruptura del código. De acuerdo con el comentario por async5 a continuación, debe reemplazar textContent.bidiTexts con textContent.items.

function Pdf2TextClass(){ 
    var self = this; 
    this.complete = 0; 

    /** 
    * 
    * @param data ArrayBuffer of the pdf file content 
    * @param callbackPageDone To inform the progress each time 
    *  when a page is finished. The callback function's input parameters are: 
    *  1) number of pages done; 
    *  2) total number of pages in file. 
    * @param callbackAllDone The input parameter of callback function is 
    *  the result of extracted text from pdf file. 
    * 
    */ 
    this.pdfToText = function(data, callbackPageDone, callbackAllDone){ 
    console.assert(data instanceof ArrayBuffer || typeof data == 'string'); 
    PDFJS.getDocument(data).then(function(pdf) { 
    var div = document.getElementById('viewer'); 

    var total = pdf.numPages; 
    callbackPageDone(0, total);   
    var layers = {};   
    for (i = 1; i <= total; i++){ 
     pdf.getPage(i).then(function(page){ 
     var n = page.pageNumber; 
     page.getTextContent().then(function(textContent){ 
      if(null != textContent.bidiTexts){ 
      var page_text = ""; 
      var last_block = null; 
      for(var k = 0; k < textContent.bidiTexts.length; k++){ 
       var block = textContent.bidiTexts[k]; 
       if(last_block != null && last_block.str[last_block.str.length-1] != ' '){ 
        if(block.x < last_block.x) 
         page_text += "\r\n"; 
        else if (last_block.y != block.y && (last_block.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null)) 
         page_text += ' '; 
       } 
       page_text += block.str; 
       last_block = block; 
      } 

      textContent != null && console.log("page " + n + " finished."); //" content: \n" + page_text); 
      layers[n] = page_text + "\n\n"; 
      } 
      ++ self.complete; 
      callbackPageDone(self.complete, total); 
      if (self.complete == total){ 
      window.setTimeout(function(){ 
       var full_text = ""; 
       var num_pages = Object.keys(layers).length; 
       for(var j = 1; j <= num_pages; j++) 
        full_text += layers[j] ; 
       callbackAllDone(full_text); 
      }, 1000);    
      } 
     }); // end of page.getTextContent().then 
     }); // end of page.then 
    } // of for 
    }); 
}; // end of pdfToText() 
}; // end of class 
+1

'Pregunta antigua' pero excelente respuesta. ¿Tienes alguna idea de cómo hacer que textLayer no represente caracteres en divs individuales sino que los represente como palabras completas? Obtuve un gran golpe de rendimiento al tratar de usar la superposición de la capa de texto con los divs en posición absoluta, ya que hay muchos de ellos. Si prefieres esto como una pregunta de StackOverflow real separada, haré una. – AJP

+0

@ gm2008 He intentado extraer texto de un PDF usando su función. Sin embargo, no puedo extraer el texto. El texto completo devuelve una cadena vacía al final. ¿Puedes ayudarme? – suzee

+0

No pude hacer que esto funcione tampoco (API ha cambiado). Agregué mi propio ejemplo a continuación. – SchizoDuckie

-2

Es posible, pero:

  • que tendría que utilizar el servidor de todos modos, no hay manera de que pueda obtener el contenido de un archivo en el ordenador del usuario sin transferirlo al servidor y volver
  • I no hay nada que haya escrito una biblioteca aún

Así que si tiene algo de tiempo libre puede aprender el formato pdf y escribir una biblioteca usted mismo, o simplemente puede usar la biblioteca del lado del servidor, por supuesto.

6

Aquí hay algo de código JavaScript que hace lo que quiere usando pdf.js de http://hublog.hubmed.org/archives/001948.html:

var input = document.getElementById("input"); 
var processor = document.getElementById("processor"); 
var output = document.getElementById("output"); 

// listen for messages from the processor 
window.addEventListener("message", function(event){ 
    if (event.source != processor.contentWindow) return; 

    switch (event.data){ 
    // "ready" = the processor is ready, so fetch the PDF file 
    case "ready": 
     var xhr = new XMLHttpRequest; 
     xhr.open('GET', input.getAttribute("src"), true); 
     xhr.responseType = "arraybuffer"; 
     xhr.onload = function(event) { 
     processor.contentWindow.postMessage(this.response, "*"); 
     }; 
     xhr.send(); 
    break; 

    // anything else = the processor has returned the text of the PDF 
    default: 
     output.textContent = event.data.replace(/\s+/g, " "); 
    break; 
    } 
}, true); 

... y aquí es un ejemplo:

http://git.macropus.org/2011/11/pdftotext/example/

+0

Mientras que esos enlaces pueden responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionan el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. –

+0

hola, estoy intentando esto, pero esto todavía requiere que se cargue un archivo al servidor. ¿Cómo puedo procesar archivos localmente, desde el lado del cliente? – Ben

+0

¿Ha probado la estrategia en la respuesta de @ gm2008? – rphv

7

no pude conseguir el ejemplo de gm2008 a trabajar (la estructura de datos interna sobre pdf.js ha cambiado aparentemente), por lo que escribió mi propia solución completamente basada en la promesa de que no utiliza ningún elemento DOM, queryselectors o lienzo, utilizando el pdf.js actualizado del ejemplo en mozilla

Come una ruta de archivo para la carga, ya que la estoy usando con node-webkit. Debe asegurarse de tener los cmaps descargados y apuntados en alguna parte y nee pdf.js y pdf.worker.js para que esto funcione.

/** 
    * Extract text from PDFs with PDF.js 
    * Uses the demo pdf.js from https://mozilla.github.io/pdf.js/getting_started/ 
    */ 
    this.pdfToText = function(data) { 

     PDFJS.workerSrc = 'js/vendor/pdf.worker.js'; 
     PDFJS.cMapUrl = 'js/vendor/pdfjs/cmaps/'; 
     PDFJS.cMapPacked = true; 

     return PDFJS.getDocument(data).then(function(pdf) { 
      var pages = []; 
      for (var i = 0; i < pdf.numPages; i++) { 
       pages.push(i); 
      } 
      return Promise.all(pages.map(function(pageNumber) { 
       return pdf.getPage(pageNumber + 1).then(function(page) { 
        return page.getTextContent().then(function(textContent) { 
         return textContent.items.map(function(item) { 
          return item.str; 
         }).join(' '); 
        }); 
       }); 
      })).then(function(pages) { 
       return pages.join("\r\n"); 
      }); 
     }); 
    } 

uso:

self.pdfToText(files[0].path).then(function(result) { 
     console.log("PDF done!", result); 
}) 
+0

Véase también https://github.com/mozilla/pdf.js/blob/master/examples/text-only/pdf2svg.js y https://github.com/mozilla/pdf.js/blob/master/examples /node/getinfo.js – async5

0

Para todas las personas que realmente desean utilizar en un servidor de nodo:

/** 
* Created by velten on 25.04.16. 
*/ 
"use strict"; 
let pdfUrl = "http://example.com/example.pdf"; 
let request = require('request'); 
var pdfParser = require('pdf2json'); 

let pdfPipe = request({url: pdfUrl, encoding:null}).pipe(pdfParser); 

pdfPipe.on("pdfParser_dataError", err => console.error(err)); 
pdfPipe.on("pdfParser_dataReady", pdf => { 
    //optionally: 
    //let pdf = pdfParser.getMergedTextBlocksIfNeeded(); 

    let count1 = 0; 
    //get text on a particular page 
    for (let page of pdf.formImage.Pages) { 
     count1 += page.Texts.length; 
    } 

    console.log(count1); 
    pdfParser.destroy(); 
}); 
Cuestiones relacionadas