Как автоматически импортировать данные из загруженного файла CSV или XLS в Google листы

У меня есть устаревшая система баз данных (недоступная в интернете) на сервере, который генерирует отчеты CSV или XLS в папку Google Drive. В настоящее время я вручную открываю эти файлы в веб-интерфейсе диска и конвертирую их в Google листы.

Я бы предпочел, чтобы это было автоматически, чтобы я мог создавать задания, которые добавляют / преобразуют и отображают данные на других листах.

можно ли вывести родной язык .gsheet файл? Или есть способ конвертировать CSV или XLS.gsheet программно после сохранения на Google Диске либо в Google Apps, либо через скрипт/утилиту на базе Windows?

3 ответов


вы можете программно импортировать данные из csv-файла на вашем диске в существующий Google лист с помощью сценария Google Apps, заменяя/добавляя данные по мере необходимости.

Ниже приведен пример кода. Он предполагает, что:a) у вас есть назначенная папка на вашем диске, где файл CSV сохраняется / загружается в;b) файл CSV называется " Отчет.csv " и данные в нем разделены запятыми; и c) данные CSV импортируются в назначенный электронная таблица. См. комментарии в коде для получения дополнительной информации.

function importData() {
  var fSource = DriveApp.getFolderById(reports_folder_id); // reports_folder_id = id of folder where csv reports are saved
  var fi = fSource.getFilesByName('report.csv'); // latest report file
  var ss = SpreadsheetApp.openById(data_sheet_id); // data_sheet_id = id of spreadsheet that holds the data to be updated with new report data

  if ( fi.hasNext() ) { // proceed if "report.csv" file exists in the reports folder
    var file = fi.next();
    var csv = file.getBlob().getDataAsString();
    var csvData = CSVToArray(csv); // see below for CSVToArray function
    var newsheet = ss.insertSheet('NEWDATA'); // create a 'NEWDATA' sheet to store imported data
    // loop through csv data array and insert (append) as rows into 'NEWDATA' sheet
    for ( var i=0, lenCsv=csvData.length; i<lenCsv; i++ ) {
      newsheet.getRange(i+1, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
    }
    /*
    ** report data is now in 'NEWDATA' sheet in the spreadsheet - process it as needed,
    ** then delete 'NEWDATA' sheet using ss.deleteSheet(newsheet)
    */
    // rename the report.csv file so it is not processed on next scheduled run
    file.setName("report-"+(new Date().toString())+".csv");
  }
};


// http://www.bennadel.com/blog/1504-Ask-Ben-Parsing-CSV-Strings-With-Javascript-Exec-Regular-Expression-Command.htm
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.

function CSVToArray( strData, strDelimiter ) {
  // Check to see if the delimiter is defined. If not,
  // then default to COMMA.
  strDelimiter = (strDelimiter || ",");

  // Create a regular expression to parse the CSV values.
  var objPattern = new RegExp(
    (
      // Delimiters.
      "(\" + strDelimiter + "|\r?\n|\r|^)" +

      // Quoted fields.
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +

      // Standard fields.
      "([^\"\" + strDelimiter + "\r\n]*))"
    ),
    "gi"
  );

  // Create an array to hold our data. Give the array
  // a default empty first row.
  var arrData = [[]];

  // Create an array to hold our individual pattern
  // matching groups.
  var arrMatches = null;

  // Keep looping over the regular expression matches
  // until we can no longer find a match.
  while (arrMatches = objPattern.exec( strData )){

    // Get the delimiter that was found.
    var strMatchedDelimiter = arrMatches[ 1 ];

    // Check to see if the given delimiter has a length
    // (is not the start of string) and if it matches
    // field delimiter. If id does not, then we know
    // that this delimiter is a row delimiter.
    if (
      strMatchedDelimiter.length &&
      (strMatchedDelimiter != strDelimiter)
    ){

      // Since we have reached a new row of data,
      // add an empty row to our data array.
      arrData.push( [] );

    }

    // Now that we have our delimiter out of the way,
    // let's check to see which kind of value we
    // captured (quoted or unquoted).
    if (arrMatches[ 2 ]){

      // We found a quoted value. When we capture
      // this value, unescape any double quotes.
      var strMatchedValue = arrMatches[ 2 ].replace(
        new RegExp( "\"\"", "g" ),
        "\""
      );

    } else {

      // We found a non-quoted value.
      var strMatchedValue = arrMatches[ 3 ];

    }

    // Now that we have our value string, let's add
    // it to the data array.
    arrData[ arrData.length - 1 ].push( strMatchedValue );
  }

  // Return the parsed data.
  return( arrData );
};

вы можете создать время-управляемый триггер в проекте скрипта importData() функция на регулярной основе (например, каждую ночь в 1AM), поэтому все, что вам нужно сделать, это поставить новый отчет.csv-файл в назначенную папку диска, и он будет автоматически обработан при следующем запланированном запуске.

Если вы абсолютно должны работать с файлами Excel вместо CSV, то вы можете использовать этот код ниже. Для него для работы необходимо включить Drive API в расширенных сервисах Google в скрипте и консоли разработчиков (см. Как включить дополнительные услуги для деталей).

/**
 * Convert Excel file to Sheets
 * @param {Blob} excelFile The Excel file blob data; Required
 * @param {String} filename File name on uploading drive; Required
 * @param {Array} arrParents Array of folder ids to put converted file in; Optional, will default to Drive root folder
 * @return {Spreadsheet} Converted Google Spreadsheet instance
 **/
function convertExcel2Sheets(excelFile, filename, arrParents) {

  var parents  = arrParents || []; // check if optional arrParents argument was provided, default to empty array if not
  if ( !parents.isArray ) parents = []; // make sure parents is an array, reset to empty array if not

  // Parameters for Drive API Simple Upload request (see https://developers.google.com/drive/web/manage-uploads#simple)
  var uploadParams = {
    method:'post',
    contentType: 'application/vnd.ms-excel', // works for both .xls and .xlsx files
    contentLength: excelFile.getBytes().length,
    headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},
    payload: excelFile.getBytes()
  };

  // Upload file to Drive root folder and convert to Sheets
  var uploadResponse = UrlFetchApp.fetch('https://www.googleapis.com/upload/drive/v2/files/?uploadType=media&convert=true', uploadParams);

  // Parse upload&convert response data (need this to be able to get id of converted sheet)
  var fileDataResponse = JSON.parse(uploadResponse.getContentText());

  // Create payload (body) data for updating converted file's name and parent folder(s)
  var payloadData = {
    title: filename, 
    parents: []
  };
  if ( parents.length ) { // Add provided parent folder(s) id(s) to payloadData, if any
    for ( var i=0; i<parents.length; i++ ) {
      try {
        var folder = DriveApp.getFolderById(parents[i]); // check that this folder id exists in drive and user can write to it
        payloadData.parents.push({id: parents[i]});
      }
      catch(e){} // fail silently if no such folder id exists in Drive
    }
  }
  // Parameters for Drive API File Update request (see https://developers.google.com/drive/v2/reference/files/update)
  var updateParams = {
    method:'put',
    headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},
    contentType: 'application/json',
    payload: JSON.stringify(payloadData)
  };

  // Update metadata (filename and parent folder(s)) of converted sheet
  UrlFetchApp.fetch('https://www.googleapis.com/drive/v2/files/'+fileDataResponse.id, updateParams);

  return SpreadsheetApp.openById(fileDataResponse.id);
}

/**
 * Sample use of convertExcel2Sheets() for testing
 **/
 function testConvertExcel2Sheets() {
  var xlsId = "0B9**************OFE"; // ID of Excel file to convert
  var xlsFile = DriveApp.getFileById(xlsId); // File instance of Excel file
  var xlsBlob = xlsFile.getBlob(); // Blob source of Excel file for conversion
  var xlsFilename = xlsFile.getName(); // File name to give to converted file; defaults to same as source file
  var destFolders = []; // array of IDs of Drive folders to put converted file in; empty array = root folder
  var ss = convertExcel2Sheets(xlsBlob, xlsFilename, destFolders);
  Logger.log(ss.getId());
}

вышеуказанный код также доступен как суть здесь.


вы можете получить Google Drive для автоматического преобразования csv-файлов в Google листы, добавив

?convert=true

до конца url-адреса api, который вы вызываете.

изменить: Вот документация по параметрам: https://developers.google.com/drive/v2/reference/files/insert

кроме того, при поиске вышеуказанной ссылки я обнаружил, что на этот вопрос уже был дан ответ здесь:

загрузить CSV на Google Диск Электронная таблица с использованием Drive V2 API


(Mar 2017) принятый ответ не является лучшим решением. Он опирается на ручной перевод с помощью скрипта приложений, и код может быть не устойчивым, требуя обслуживания. Если ваша устаревшая система автогенерирует CSV-файлы, лучше всего они переходят в другую папку для временной обработки (импорт [загрузка на Google Диск и преобразование] в файлы Google Sheets).

моя мысль заключается в том, чтобы позволить API-интерфейсу привода выполнять всю тяжелую работу. The Google Drive API команда выпущен v3 в конце 2015 года, и в этом выпуске insert() изменить имена create() чтобы лучше отражать файловую операцию. Также больше нет флага convert - вы просто указываете типы MIMEtypes... только представьте!

документация также была улучшена: теперь специальное руководство, посвященное передает (простые, составные, и возобновляемые), который поставляется с примерами кода на Java, и на Python, PHP, с#/.Чистая, Рубин, JavaScript с/узел.js и iOS / Obj-C это импортирует CSV-файлы в формат Google листов по желанию.

ниже приведено одно альтернативное решение Python для коротких файлов ("простая загрузка"), где вы не нужны apiclient.http.MediaFileUpload класса. Этот фрагмент предполагает, что ваш код аутентификации работает там, где ваша конечная точка службы DRIVE С минимальным объемом auth https://www.googleapis.com/auth/drive.file.

# filenames & MIMEtypes
DST_FILENAME = 'inventory'
SRC_FILENAME = DST_FILENAME + '.csv'
SHT_MIMETYPE = 'application/vnd.google-apps.spreadsheet'
CSV_MIMETYPE = 'text/csv'

# Import CSV file to Google Drive as a Google Sheets file
METADATA = {'name': DST_FILENAME, 'mimeType': SHT_MIMETYPE}
rsp = DRIVE.files().create(body=METADATA, media_body=SRC_FILENAME).execute()
if rsp:
    print('Imported %r to %r (as %s)' % (SRC_FILENAME, DST_FILENAME, rsp['mimeType']))

еще лучше, а не загружать в My Drive, вы загружаете в одну(или несколько) определенную папку (ы), что означает, что вы добавите идентификатор(Ы) родительской папки) к METADATA. (Также см. Пример кода на на этой странице. И, наконец, нет туземцев .gsheet "file" -- этот файл просто имеет ссылку на онлайн-лист, так что выше то, что вы хотите сделать.

если вы не используете Python, вы можете использовать фрагмент выше в качестве псевдокода для порта на ваш системный язык. Независимо от того, есть гораздо меньше кода, потому что нет разбора CSV-файла. Единственное, что осталось, - это сдуть временную папку CSV-файла, которую написала ваша устаревшая система к.