Javascript 如何在JavaSript中从PDF中提取文本

Javascript 如何在JavaSript中从PDF中提取文本,javascript,pdf,text,Javascript,Pdf,Text,我想知道是否可以只使用Javascript来获取PDF文件中的文本? 如果是,有人能告诉我怎么做吗 我知道有一些服务器端java、c#等库,但我不希望使用服务器。 谢谢这是可能的,但是: 无论如何,您都必须使用服务器,如果不将文件传输到服务器并返回,就无法在用户计算机上获取文件内容 我认为还没有人写过这样的图书馆 因此,如果您有一些空闲时间,您可以学习pdf格式并自己编写这样的库,或者您当然可以使用服务器端库。以下是一些JavaScript代码,可以实现您使用pdf.js所需的功能: …下面

我想知道是否可以只使用Javascript来获取PDF文件中的文本? 如果是,有人能告诉我怎么做吗

我知道有一些服务器端java、c#等库,但我不希望使用服务器。 谢谢

这是可能的,但是:

  • 无论如何,您都必须使用服务器,如果不将文件传输到服务器并返回,就无法在用户计算机上获取文件内容
  • 我认为还没有人写过这样的图书馆

因此,如果您有一些空闲时间,您可以学习pdf格式并自己编写这样的库,或者您当然可以使用服务器端库。

以下是一些JavaScript代码,可以实现您使用pdf.js所需的功能:

…下面是一个例子:


这是一个古老的问题,但由于pdf.js多年来一直在发展,我想给出一个新的答案。也就是说,它可以在本地完成,而不涉及任何服务器或外部服务。新的pdf.js有一个函数:page.getTextContent()。您可以从中获取文本内容。我已经用下面的代码成功地完成了它

  • 你在每一步中得到的都是一个承诺。您需要这样编码:
    。然后(function(){…})
    继续下一步

    1)
    PDFJS.getDocument(数据)。然后(函数(pdf){

    2)
    pdf.getPage(i).then(函数(页面){

    3)
    page.getTextContent().then(函数(textContent){

  • 您最终得到的是一个字符串数组
    textContent.bidiTexts[]
    。您将它们连接起来以获得1页的文本。文本块的坐标用于判断是否需要插入换行符或空格。(这可能不完全可靠,但从我的测试来看似乎还可以。)

  • 输入参数
    data
    需要是URL或ArrayBuffer类型的数据。我使用
    FileReader
    API中的ReadAsArrayBuffer(文件)函数来获取数据

  • 希望这有帮助

    注意:根据其他一些用户的说法,该库已更新并导致代码中断。根据下面async5的评论,您需要将
    textContent.bidiTexts
    替换为
    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
    
    函数Pdf2TextClass(){
    var self=这个;
    此值为0.complete=0;
    /**
    *
    *pdf文件内容的@param data ArrayBuffer
    *@param callbackPageDone每次通知进度
    *页面完成时。回调函数的输入参数为:
    *1)完成的页数;
    *2)文件中的总页数。
    *@param callbackAllDone回调函数的输入参数为
    *从pdf文件中提取文本的结果。
    *
    */
    this.pdfToText=函数(数据、callbackPageDone、callbackAllDone){
    assert(ArrayBuffer | | typeof data=='string');
    getDocument(数据).then(函数)(pdf){
    var div=document.getElementById('viewer');
    var total=pdf.numPages;
    callbackPageDone(0,总计);
    var层={};
    
    例如(i=1;i我无法让gm2008的示例正常工作(pdf.js上的内部数据结构显然发生了变化),因此我编写了自己的完全基于承诺的解决方案,它不使用任何DOM元素、QuerySelector或canvas,使用的是在

    它会吃掉上传的文件路径,因为我将它与node webkit一起使用。 您需要确保已下载CMAP并指向某个位置,并且需要使用pdf.js和pdf.worker.js才能使其正常工作

        /**
         * 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");
                });
            });
        }
    

    对于所有实际希望在节点服务器上使用它的人:

    /**
     * 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();
    });
    

    注意:此代码假设您使用的是nodejs。这意味着您正在解析本地文件,而不是网页中的文件,因为原始问题没有明确询问解析网页上的PDF

    @gm2008的答案是一个很好的起点(请阅读它和它的评论以获取更多信息),但需要一些更新(08/19)和一些未使用的代码。我也喜欢更完整的示例。可以进行更多的重构和调整(例如使用
    wait
    ),但现在它尽可能接近原始答案

    和以前一样,它使用Mozilla的PDFjs库

    根据我的经验,这在找到放置空间的位置方面做得不好,但这是下一次的问题

    [编辑:我相信对
    .transform
    使用的更新已将空白恢复为原来的状态。]

    //此文件名为mypdffieltotext.js,位于根文件夹中
    设PDFJS=require('PDFJS-dist');
    让pathToPDF='path/to/mypdffieltotext.pdf';
    设toText=Pdf2TextObj();
    让onPageDone=function(){};//不希望在页面之间执行任何操作
    让onFinish=function(全文){console.log(全文)};
    pdfToText(路径topdf、onPageDone、onFinish);
    函数Pdf2TextObj(){
    让自我=这个;
    此值为0.complete=0;
    /**
    *
    *@param path指向pdf文件的路径。
    *@param callbackPageDone每次通知进度
    *页面完成时。回调函数的输入参数为:
    *1)完成的页数。
    *2)文件中的总页数。
    *3)`page`对象本身或null。
    *在收集所有文本后调用@param callbackAllDone。输入参数:
    *1)已解析pdf的全文。
    *
    */
    this.pdfToText=函数(路径、callbackPageDone、callbackAllDone){
    //assert(typeof path=='string');
    getDocument(path).promise.then(函数)(pdf){
    让total=pdf.numPages;
    callbackPageDone(0,总计,空);
    让pages={};
    //出于某些(pdf?)原因,这些并不是连续出现的
    //顺序。这就是为什么它们被存储为一个对象,然后
    
     self.pdfToText(files[0].path).then(function(result) {
          console.log("PDF done!", result);
     })
    
    /**
     * 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();
    });
    
    <script src="https://npmcdn.com/pdfjs-dist/build/pdf.js"></script>
        <script>
        
    function Pdf2TextClass(){
        var self = this;
        this.complete = 0;
    
        this.pdfToText = function(data, callbackPageDone, callbackAllDone){
        console.assert( data  instanceof ArrayBuffer  || typeof data == 'string' );
        var loadingTask = pdfjsLib.getDocument(data);
        loadingTask.promise.then(function(pdf) {
    
    
        var total = pdf._pdfInfo.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){
           
           //console.log(textContent.items[0]);0
             if( null != textContent.items ){
               var page_text = "";
               var last_block = null;
               for( var k = 0; k < textContent.items.length; k++ ){
                   var block = textContent.items[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] ;
                 console.log(full_text);
               }, 1000);              
             }
           }); // end  of page.getTextContent().then
         }); // end of page.then
       } // of for
     });
    }; // end of pdfToText()
    }; // end of class
    var pdff = new Pdf2TextClass();
    pdff.pdfToText('PDF_URL');
        </script>