Получить pdf-вложения из Gmail в виде текста

Я искал в Интернете и переполнении стека, но не нашел решения. Я пытаюсь сделать следующее: я получаю определенные вложения по почте, которые я хотел бы иметь в виде (простого) текста для дальнейшей обработки. Мой сценарий выглядит так:

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});
    }
}

К сожалению, это не работает. У кого-нибудь здесь есть идея, как я могу это сделать? Это вообще возможно?

Заранее большое спасибо.

Бест, Фил

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 ()

Эта утилита доступна в виде сущности. Там приведены несколько примеров.

Предыдущий ответ показал, что можно было использовать Drive API insert метод для OCR, но он не предоставил детали кода. С появлением расширенных сервисов Google API Drive легко доступен из скрипта Google Apps. Вам нужно включить и включить Drive API от редактора, под Resources > Advanced Google Services,

pdfToText() использует сервис Drive для создания Google Doc из содержимого файла PDF. К сожалению, это содержит "картинки" каждой страницы в документе - мы мало что можем с этим поделать. Затем он использует обычный 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
  }
}

Преобразованию в 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()); 
}
Другие вопросы по тегам