web-dev-qa-db-fra.com

Comment importer automatiquement des données d'un fichier CSV ou XLS importé dans Google Sheets

J'ai un système de base de données hérité (non accessible sur le Web) sur un serveur qui génère des rapports CSV ou XLS dans un dossier Google Drive. Actuellement, j'ouvre manuellement ces fichiers dans l'interface Web de Drive et les convertis en Google Sheets.

Je préférerais que cela soit automatique afin de pouvoir créer des travaux qui ajoutent/transforment et tracent les données dans d'autres feuilles.

Est-il possible de générer un fichier .gsheet natif? Ou existe-t-il un moyen de convertir un fichier CSV ou XLS en .gsheet par programme après l'avoir enregistré sur Google Drive, soit dans Google Apps, soit via un script/utilitaire Windows?

32
youcantexplainthat

Vous pouvez importer par programme des données d'un fichier csv de votre lecteur dans une feuille Google existante à l'aide du script Google Apps, en remplaçant/ajoutant des données si nécessaire.

Vous trouverez ci-dessous un exemple de code. Il suppose que: a) vous avez un dossier désigné sur votre lecteur dans lequel le fichier CSV est enregistré/chargé; b) le fichier CSV s'appelle "report.csv" et les données qu'il contient sont délimitées par des virgules; et c) les données CSV sont importées dans une feuille de calcul désignée. Voir les commentaires dans le code pour plus de détails.

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

Vous pouvez ensuite créer déclencheur induit par le temps dans votre projet de script pour exécuter la fonction importData() sur une base régulière (par exemple, tous les soirs à 1 heure du matin); report.csv dans le dossier Drive désigné et il sera automatiquement traité lors de la prochaine exécution planifiée.

Si vous DEVEZ absolument travailler avec des fichiers Excel au lieu de CSV, vous pouvez utiliser ce code ci-dessous. Pour que cela fonctionne, vous devez activer l'API de lecteur dans les services Google avancés dans votre script et dans la console des développeurs (voir Comment activer les services avancés pour plus de détails).

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

Le code ci-dessus est également disponible en tant que Gist ici .

35
azawaza

Vous pouvez faire en sorte que Google Drive convertisse automatiquement les fichiers csv en Google Sheets en ajoutant

?convert=true

jusqu’à la fin de l’API url que vous appelez.

EDIT: Voici la documentation sur les paramètres disponibles: https://developers.google.com/drive/v2/reference/files/insert

Aussi, en cherchant le lien ci-dessus, j'ai trouvé que cette question a déjà été posée ici:

Télécharger un fichier CSV sur une feuille de calcul Google Drive à l'aide de l'API Drive v2

7
Matt

(mars 2017) La réponse acceptée n'est pas la meilleure solution. Il repose sur une traduction manuelle à l'aide du script Apps, et le code peut ne pas être résilient, nécessitant une maintenance. Si votre système hérité génère automatiquement des fichiers CSV, il est préférable de les placer dans un autre dossier pour un traitement temporaire (importation [téléchargement vers Google Drive et conversion] vers des fichiers Google Sheets).

Mon idée est de laisser l'API de lecteur faire le gros du travail. L'équipe API de Google Drive team publiée v à la fin de 2015 et dans cette version, insert() a changé le nom et devient create() donc afin de mieux refléter le fonctionnement du fichier. Il n'y a pas non plus d'indicateur de conversion: vous spécifiez simplement des types MIME ... imaginez cela!

La documentation a également été améliorée: il existe maintenant un guide spécial consacré aux téléchargements (simple, en plusieurs parties et pouvant être repris) qui contient un exemple de code en Java, Python, PHP, C #/.NET, Ruby, JavaScript. /Node.js et iOS/Obj-C qui importe les fichiers CSV au format Google Sheets selon les besoins.

Vous trouverez ci-dessous une solution alternative Python pour les fichiers courts ("téléchargement simple")) où vous n'avez pas besoin du apiclient.http.MediaFileUpload classe. Cet extrait suppose que votre code d'authentification fonctionne lorsque votre point de terminaison de service est DRIVE avec une étendue minimale d'authentification de 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']))

Mieux encore, plutôt que de télécharger sur My Drive, vous téléchargeriez vers un (ou plusieurs) dossier (s) spécifique (s), ce qui signifie que vous ajouteriez le ou les ID de dossier parent à METADATA. (Voir également l'exemple de code sur cette page .) Enfin, il n'y a pas de "fichier" natif. Ce fichier ne contient qu'un lien vers la fiche en ligne. Vous devez donc choisir ci-dessus. .

Si vous n'utilisez pas Python, vous pouvez utiliser l'extrait de code ci-dessus comme pseudocode pour le transférer dans la langue de votre système. Quoi qu'il en soit, il y a beaucoup moins de code à gérer car il n'y a pas d'analyse CSV. La seule chose qui reste à faire est de supprimer le dossier temp du fichier CSV dans lequel votre ancien système avait été écrit.

6
wescpy

Au cas où quelqu'un chercherait - j'ai créé un utilitaire pour l'importation automatisée de fichiers xlsx dans une feuille de calcul Google: xls2sheets . On peut le faire automatiquement en configurant le cronjob pour ./cmd/sheets-refresh, le readme décrit tout. J'espère que cela vous sera utile.

0
Pukeko