【问题标题】:Get pdf-attachments from Gmail as text从 Gmail 获取 pdf 附件作为文本
【发布时间】:2015-05-13 05:54:30
【问题描述】:

我搜索了网络和 Stack Overflow,但没有找到解决方案。我尝试做的是以下内容:我通过邮件获得某些附件,我希望将其作为(纯)文本进行进一步处理。我的脚本如下所示:

function MyFunction() {

  var threads = GmailApp.search ('label:templabel'); 
  var messages = GmailApp.getMessagesForThreads(threads); 

   for (i = 0; i < messages.length; ++i)
   {
     j = messages[i].length; 
   var messageBody = messages[i][0].getBody(); 
   var messageSubject = messages [i][0].getSubject();
     var attach = messages [i][0].getAttachments();
     var attachcontent = attach.getContentAsString();
    GmailApp.sendEmail("mail", messageSubject, "", {htmlBody: attachcontent});
    }
}

不幸的是,这不起作用。这里有人知道我该怎么做吗?有可能吗?

非常感谢您。

最好的,菲尔

【问题讨论】:

    标签: pdf text google-apps-script gmail email-attachments


    【解决方案1】:

    编辑:为 DriveApp 更新,因为 DocsList 已弃用。


    我建议将其分解为两个问题。第一个是如何从电子邮件中获取 pdf 附件,第二个是如何将该 pdf 转换为文本。

    正如您所发现的,getContentAsString() 不会神奇地将 pdf 附件更改为纯文本或 html。我们需要做一些更复杂的事情。

    首先,我们将以Blob 的形式获取附件,这是多个服务用来交换数据的实用程序类。

    var blob = attachments[0].getAs(MimeType.PDF);
    

    因此,分离出第二个问题,并假设我们只对标记为templabel 的每个线程的第一条消息的第一个附件感兴趣,下面是myFunction() 的外观:

    /**
     * Get messages labeled 'templabel', and send myself the text contents of
     * pdf attachments in new emails.
     */
    function myFunction() {
    
      var threads = GmailApp.search('label:templabel');
      var threadsMessages = GmailApp.getMessagesForThreads(threads);
    
      for (var thread = 0; thread < threadsMessages.length; ++thread) {
        var message = threadsMessages[thread][0];
        var messageBody = message.getBody();
        var messageSubject = message.getSubject();
        var attachments = message.getAttachments();
    
        var blob = attachments[0].getAs(MimeType.PDF);
        var filetext = pdfToText( blob, {keepTextfile: false} );
    
        GmailApp.sendEmail(Session.getActiveUser().getEmail(), messageSubject, filetext);
      }
    }
    

    我们依靠辅助函数 pdfToText() 将我们的 pdf blob 转换为文本,然后我们将其作为纯文本电子邮件发送给自己。这个辅助函数有多种选择;通过设置keepTextfile: false,我们选择让它将PDF文件的文本内容返回给我们,而不在我们的云端硬盘中留下任何残留文件。

    pdfToText()

    此实用程序可用as a gist。那里提供了几个例子。

    previous answer 表示可以使用 Drive API 的 insert 方法来执行 OCR,但它没有提供代码详细信息。随着高级 Google 服务的引入,可以从 Google Apps 脚本轻松访问 Drive API。您确实需要在 Resources &gt; Advanced Google Services 下的编辑器中打开并启用 Drive API

    pdfToText() 使用 Drive 服务从 PDF 文件的内容生成 Google Doc。不幸的是,这包含文档中每一页的“图片”——我们对此无能为力。然后它使用常规的DocumentService 将文档正文提取为纯文本。

    /**
     * See gist: https://gist.github.com/mogsdad/e6795e438615d252584f
     *
     * Convert pdf file (blob) to a text file on Drive, using built-in OCR.
     * By default, the text file will be placed in the root folder, with the same
     * name as source pdf (but extension 'txt'). Options:
     *   keepPdf (boolean, default false)     Keep a copy of the original PDF file.
     *   keepGdoc (boolean, default false)    Keep a copy of the OCR Google Doc file.
     *   keepTextfile (boolean, default true) Keep a copy of the text file.
     *   path (string, default blank)         Folder path to store file(s) in.
     *   ocrLanguage (ISO 639-1 code)         Default 'en'.
     *   textResult (boolean, default false)  If true and keepTextfile true, return
     *                                        string of text content. If keepTextfile
     *                                        is false, text content is returned without
     *                                        regard to this option. Otherwise, return
     *                                        id of textfile.
     *
     * @param {blob}   pdfFile    Blob containing pdf file
     * @param {object} options    (Optional) Object specifying handling details
     *
     * @returns {string}          id of text file (default) or text content
     */
    function pdfToText ( pdfFile, options ) {
      // Ensure Advanced Drive Service is enabled
      try {
        Drive.Files.list();
      }
      catch (e) {
        throw new Error( "To use pdfToText(), first enable 'Drive API' in Resources > Advanced Google Services." );
      }
    
      // Set default options
      options = options || {};
      options.keepTextfile = options.hasOwnProperty("keepTextfile") ? options.keepTextfile : true;
    
      // Prepare resource object for file creation
      var parents = [];
      if (options.path) {
        parents.push( getDriveFolderFromPath (options.path) );
      }
      var pdfName = pdfFile.getName();
      var resource = {
        title: pdfName,
        mimeType: pdfFile.getContentType(),
        parents: parents
      };
    
      // Save PDF to Drive, if requested
      if (options.keepPdf) {
        var file = Drive.Files.insert(resource, pdfFile);
      }
    
      // Save PDF as GDOC
      resource.title = pdfName.replace(/pdf$/, 'gdoc');
      var insertOpts = {
        ocr: true,
        ocrLanguage: options.ocrLanguage || 'en'
      }
      var gdocFile = Drive.Files.insert(resource, pdfFile, insertOpts);
    
      // Get text from GDOC  
      var gdocDoc = DocumentApp.openById(gdocFile.id);
      var text = gdocDoc.getBody().getText();
    
      // We're done using the Gdoc. Unless requested to keepGdoc, delete it.
      if (!options.keepGdoc) {
        Drive.Files.remove(gdocFile.id);
      }
    
      // Save text file, if requested
      if (options.keepTextfile) {
        resource.title = pdfName.replace(/pdf$/, 'txt');
        resource.mimeType = MimeType.PLAIN_TEXT;
    
        var textBlob = Utilities.newBlob(text, MimeType.PLAIN_TEXT, resource.title);
        var textFile = Drive.Files.insert(resource, textBlob);
      }
    
      // Return result of conversion
      if (!options.keepTextfile || options.textResult) {
        return text;
      }
      else {
        return textFile.id
      }
    }
    

    utility from Bruce McPherson 有助于转换为 DriveApp:

    // From: http://ramblings.mcpher.com/Home/excelquirks/gooscript/driveapppathfolder
    function getDriveFolderFromPath (path) {
      return (path || "/").split("/").reduce ( function(prev,current) {
        if (prev && current) {
          var fldrs = prev.getFoldersByName(current);
          return fldrs.hasNext() ? fldrs.next() : null;
        }
        else { 
          return current ? null : prev; 
        }
      },DriveApp.getRootFolder()); 
    }
    

    【讨论】:

    • @HappyLearner 谢谢,很高兴得到赞赏!
    • 不客气。你应得的!是否有任何简单的解决方案可以可视化来转换大于 5120GB 文件大小限制的 .pdf 文件?也许是一个可恢复的请求?我注意到在uploadType 参数described here 下对它的引用,但我不知道如何开始构建它。如果您认为我应该这样做,我可以将这个问题作为一个实际的单独问题发布,这会有所帮助吗?
    • 不容易,不。您应该将其作为另一个问题发布,其他人可能对此有经验。
    • 完成。 Here is the new question。再次感谢!
    • 有效!请务必在高级部分和开发者控制台中启用 Drive API(高级部分底部的链接)
    猜你喜欢
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 2011-08-27
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    相关资源
    最近更新 更多