Jak automatycznie importować dane z przesłanego pliku CSV lub XLS do Arkuszy Google

Mam starszy system bazodanowy (niedostępny w sieci) na serwerze, który generuje raporty CSV lub XLS do folderu dysku Google. Obecnie ręcznie otwieram te pliki w interfejsie Drive web i konwertuję je na Arkusze Google.

Wolałbym, aby to było automatyczne, aby móc tworzyć zadania, które dołączają/przekształcają i wykresują dane w innych arkuszach.

Czy możliwe jest wyjście natywnego .plik gsheet? Czy istnieje sposób na konwersję CSV lub XLS do .gsheet programowo po zapisaniu go na Dysku Google w Google Apps lub za pomocą skryptu/narzędzia opartego na systemie Windows?

Author: youcantexplainthat, 2014-11-11

3 answers

Możesz programowo importować dane z pliku csv na dysku do istniejącego arkusza Google za pomocą skryptu Google Apps, zastępując / dołączając dane w razie potrzeby.

Poniżej przykładowy kod. Zakłada się, że: a) masz wyznaczony folder na dysku, do którego zapisany/przesłany jest plik CSV; b) plik CSV ma nazwę "report.csv " i dane w nim rozdzielane przecinkami; oraz C) DANE CSV są importowane do wyznaczonego arkusza kalkulacyjnego. Zobacz komentarze w kodzie więcej szczegółów.

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

Możesz następnie utworzyć WYZWALACZ czasowy w swoim projekcie skryptu, aby uruchamiać funkcję importData() regularnie (np. co noc o 1 w nocy), więc wystarczy umieścić nowy raport.plik csv do wyznaczonego folderu dysku i zostanie automatycznie przetworzony przy następnym zaplanowanym uruchomieniu.

Jeśli koniecznie musisz pracować z plikami Excel zamiast CSV, możesz użyć poniższego kodu. Aby to działało, musisz włączyć Drive API w zaawansowanym Google Usługi w skrypcie i w konsoli programistów (zobacz Jak włączyć zaawansowane usługi po szczegóły).

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

Powyższy kod jest również dostępny jako gist tutaj .

 33
Author: azawaza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-12 03:18:02

Możesz uzyskać Dysk Google, aby automatycznie konwertować pliki csv na Arkusze Google, dołączając

?convert=true

Do końca adresu URL api, który wywołujesz.

Edytuj: Oto dokumentacja dostępnych parametrów: https://developers.google.com/drive/v2/reference/files/insert

Również, szukając powyższego linku, znalazłem już odpowiedź na to pytanie tutaj:

Prześlij plik CSV do arkusza kalkulacyjnego Dysku Google za pomocą interfejsu Drive V2 API

 7
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:02

(Mar 2017) przyjęta odpowiedź nie jest najlepszym rozwiązaniem. Opiera się na ręcznym tłumaczeniu za pomocą skryptu aplikacji, a kod może nie być odporny, wymagając konserwacji. Jeśli twój stary system automatycznie generuje pliki CSV, najlepiej jest przejść do innego folderu w celu tymczasowego przetworzenia(importowanie [przesyłanie na Dysk Google i konwersja] do plików Arkuszy Google).

Moją myślą jest pozwolić, aby API Drive wykonało wszystkie ciężkie prace. Google Drive API team wydany v3 pod koniec 2015 roku i w tym wydaniu insert() zmieniono nazwy na create(), aby lepiej odzwierciedlić działanie plików. Nie ma też znacznika convert - wystarczy podać typy MIME... wyobraź to sobie!

Dokumentacja została również ulepszona: istnieje teraz specjalny przewodnik poświęcony przesyłaniu (prosty, wieloczęściowy i wznawialny), który zawiera przykładowy kod w Javie, Pythonie, PHP, C#/. Net, Ruby, JavaScript/Node.js, oraz iOS / Obj-C, który importuje pliki CSV do Arkuszy Google Formatuj zgodnie z życzeniem.

Poniżej znajduje się jedno alternatywne rozwiązanie Pythona dla krótkich plików ("simple upload"), gdzie nie potrzebujesz klasy apiclient.http.MediaFileUpload. Ten fragment zakłada, że kod auth działa tam, gdzie znajduje się punkt końcowy usługi DRIVE z minimalnym zakresem 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']))

Jeszcze lepiej, zamiast wysyłać do My Drive, należy przesłać do jednego (lub więcej) określonego folderu (- ów), co oznacza, że należy dodać ID (- y) folderów nadrzędnych do METADATA. (Zobacz także przykład kodu na tej stronie.) Wreszcie, nie ma tubylców .gsheet "plik" -- ten plik ma tylko link do arkusza online, więc to, co jest powyżej, jest tym, co chcesz zrobić.

Jeśli nie używasz Pythona, możesz użyć powyższego fragmentu jako pseudokodu do przeniesienia do języka systemowego. Niezależnie od tego, jest znacznie mniej kodu do utrzymania, ponieważ nie ma parsowania CSV. Jedyne, co pozostało, to zdmuchnąć folder tymczasowy pliku CSV, do którego zapisał się twój poprzedni system.

 6
Author: wescpy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 15:49:59