Using the Drive API3, I'm looking for a way to make a copy of a CSV file in Google Sheets format, without having to convert the text to numbers, nor the functions and dates as it can be proposed in the Google Sheets menu:
File>Import>(Select your CSV file)> Untick "Convert text to number, dates and formula".
At the moment, I've got something such as :
function convert(){
var file = DriveApp.getFileById('1234');
var resource = { title : "Title", mimeType : MimeType.GOOGLE_SHEETS,parents : [{id: file.getParents().next().getId()}],}
Drive.Files.copy(resource,file.getId())
}
To illustrate my example : I've got a text in my CSV file "2021-25-03", if I run my macro, the new spreadsheet will automaticaly format my text to a Date and that's not my goal.
TFR.
There doesn't seem to be a setting in the API or in Apps Script to prevent the automatic conversion of numbers and dates, but we can build a script to work around this. Two tools are useful:
Apps Script's Utilities.parseCsv() method, which will build a 2D array of the values in the CSV file (as pure text--it does not interpret numbers and dates).
The fact that Google Sheets interprets any value starting with a single quote ' as text. This is true whether the value is entered in the UI or programmatically.
So the overall strategy is:
Copy the file as you are doing (or just create a new blank file, as we will write the values to it).
Parse the CSV values and prepend a ' to each one.
Write these modified values to the sheet.
Something like this:
function convert(){
var file = DriveApp.getFileById(CSV_FILE_ID);
// Create the copy:
var resource = { title : "Title", mimeType : MimeType.GOOGLE_SHEETS,parents : [{id: file.getParents().next().getId()}],}
var sheetsFile = Drive.Files.copy(resource,file.getId())
// Parse the original csv file:
var csv = Utilities.parseCsv(file.getBlob().getDataAsString())
// csv is a 2D array; prepend each value with a single quote:
csv.forEach(function(row){
row.forEach(function(value, i){
row[i] = "'" + value
})
})
// Open the first (and only) sheet in the file and overwrite the values with these modified ones:
var sheet = SpreadsheetApp.openById(sheetsFile.id).getSheets()[0]
sheet.getRange(1,1,csv.length, csv[0].length).setValues(csv)
}
I want to import my csv as a 2d array within appscript, I don't want to export it to sheets, I just want to use the data to create google forms.
The csv is located on the google drive so I want to import from my google drive into a 2d array variable.
I tried multiple attempts of similar iterations of this.
function importCSVFromGoogleDrive() {
var slotadata = Utilities.parseCsv(DriveApp.getFilesByName("Slot A.csv").next())
}
To check if it is a 2d array I logged the slotadata and its length in the logger, but it returns as [20-11-08 15:27:15:880 GMT][['Slot A.csv']]
tl;dr how to import csv from drive into variable as 2d array on GAS (Google App Script)
.next() is simply returning the File, but you need to get the content within the file. (Remember that Utilities.parseCsv() expects a string.) You can use getBlob() and getDataAsString() to get that content.
function importCSVFromGoogleDrive() {
var files = DriveApp.getFilesByName("Slot A.csv");
var firstFile = files.next(); // If there's another file called "Slot A.csv", this may not be the correct file!
var slotadata = Utilities.parseCsv(firstFile.getBlob().getDataAsString());
}
I have an folder in a Google Drive which contains Archives of the last 40 years. I want to get the name of each of the file in this folder with their ids in a Google Sheet.
I wrote a Google Script to read all the content of the folder and to append the informations of each file on a specific Google Sheet. The Google Sheet is totally cleare and reconstructed each time I run the script.
while(contenuDossierRapports.hasNext()) {
rapport = contenuDossierRapports.next();
nom_rapport = rapport.getName().split(".")[0];
id = rapport.getId();
telechargement = "https://drive.google.com/uc?export=download&id=" + id;
if (nom_rapport != "Rapports") {
feuille.appendRow( [ nom_rapport, telechargement, id] );
}
}
A Google Script can only run for a total of 6 minutes top and since I have too many files, the script only has time to write the informations of around 2000 files. Do you have an idea on how to achieve what I want without having to upgrade my account?
You might be able to get just the file id's and then do them in batches of 1000.
function getFileNames() {
var fA=[];
var folder=DriveApp.getFolderById('FolderId')
var files=folder.getFiles();
while(files.hasNext()) {
fA.push(files.next().getId());
}
Logger.log(fA.join('~~~'));
}
However you do it. It boils down to figuring out how to do it in smaller batches.
I have just started to learn Google Apps Script to solve one practical task. I'd like to write a script that periodically exports all contacts in my Google account into a CSV file and sends it to a predefined email address. This should be a kind of automatic versioned backup if data loss will occur in my contact list.
Actually what I am trying to do is to use the native export functionality available in the web interface of the Google contacts (More > Export) in my script. I skimmed through the Google API, but I could not find a service or object in the Google API that does what I need. Is it possible at all?
Here's something I threw together to get a few of the basic fields in your contacts into something that could be a csv output. You may want to add more fields and perhaps use different delimiters.
function getAllContacts() {
var contactsA=ContactsApp.getContacts();
var s='';
var br='<br />';//line delimiter change to linefeed when not using html dialog
var dlm=' ~~~ ';//field delimiter
for(var i=0;i<contactsA.length;i++)
{
s+=Utilities.formatString('<br />\'%s\',\'%s\',\'%s\',\'%s\',\'%s\'%s',
(typeof(contactsA[i].getFullName())!='undefined')?contactsA[i].getFullName():'',
(typeof(contactsA[i].getAddresses().map(function (v,i,A) { return A[i].getAddress();}))!='undefined')?contactsA[i].getAddresses().map(function (v,i,A) { return A[i].getAddress();}).join(dlm):'',
(typeof(contactsA[i].getEmails().map(function(v,i,A) {return A[i].getAddress();}))!='undefined')?contactsA[i].getEmails().map(function(cV,i,A) {return A[i].getAddress();}).join(dlm):'',
(typeof(contactsA[i].getPhones().map(function(v,i,A){return A[i].getPhoneNumber();}))!='undefined')?contactsA[i].getPhones().map(function(v,i,A){return A[i].getPhoneNumber();}).join(dlm):'',
(typeof(contactsA[i].getCompanies().map(function(v,i,A){return A[i].getCompanyName();}))!='undefined')?contactsA[i].getCompanies().map(function(v,i,A){return A[i].getCompanyName();}).join(dlm):'',br);
}
var ui=HtmlService.createHtmlOutput(s).setWidth(800) ;
SpreadsheetApp.getUi().showModelessDialog(ui, 'Contacts')
}
I'm sorry if this is an obvious question, I'm still pretty new to the API.
I'm using the python drive api library, and trying to download a google spreadsheet as a csv.
When I used files.get, it spat out a file with no downloadUrl, and with no 'text/csv' key in the export links field.
If it's not possible, I can find a workaround, but I'm hoping it is, since it is possible to do manually (file->download_as->csv)
Do I need to use the google document list api?
thanks,
Matt
Update: I have posted another answer that works with the Spreadsheets v4 API.
Old Answer:
The answer from Alain is correct, but you also need to set the gid=parameter to specify which worksheet to export.
For example, if your 'application/pdf' export link is like this:
docs.google.com/feeds/download/spreadsheets/Export?key=<FILE_ID>&exportFormat=pdf
You can just change it to this to download the first worksheet:
docs.google.com/feeds/download/spreadsheets/Export?key<FILE_ID>&exportFormat=csv&gid=0
There is a bit of a problem, though as there is no reliable way to get the gid for a given worksheet through the API and they are not zero based indexes. If you delete a worksheet, that gid does not get reused. You can see the gid in the URL in your browser though, so if your worksheet information is constant you can just get that from there. See http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=1813 and http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3240 for more info on that problem.
As a lot of other people have pointed out, my original answer is somewhat outdated. So here is my answer updated for v4 of the Google Spreadsheets API. Now there's a way to get the gids, but we can't use the the drive files.export API because it only exports first worksheet in the spreadsheet (even if you specify the gid).
To export all of the worksheets as CSV files, you need to get the gids for the worksheets you want to export using the spreadsheets.get API. That API call returns a bunch of information about the spreadsheet including each of the worksheets. You can get the gid from the properties.sheetId property for each worksheet.
Once you have that, you can just build the same URL that the Sheets uses when you select File->Download As->CSV. You can take the data.spreadsheetUrl value from spreadsheets.get and replace /edit with /export and then add the gid as the parameter. You will also need to include Authorization Bearer <auth token> in the HTTP header in the request.
Here's a python script based on their quickstart example that downloads all of the sheets for the spreadsheet with a specified ID. You need to replace <spreadsheet id> with the ID for a spreadsheet you have access to:
import apiclient.discovery
import httplib2
import oauth2client.file
import oauth2client.tools
import re
import requests
import shutil
import urllib.parse
SCOPES = 'https://www.googleapis.com/auth/drive.readonly'
SPREADSHEET_ID = '<spreadsheet id>'
store = oauth2client.file.Storage('credentials.json')
creds = store.get()
if not creds or creds.invalid:
flow = oauth2client.client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = oauth2client.tools.run_flow(flow, store)
service = apiclient.discovery.build('sheets', 'v4', http=creds.authorize(httplib2.Http()))
result = service.spreadsheets().get(spreadsheetId = SPREADSHEET_ID).execute()
urlParts = urllib.parse.urlparse(result['spreadsheetUrl'])
path = re.sub("\/edit$", '/export', urlParts.path)
urlParts = urlParts._replace(path=path)
headers = {
'Authorization': 'Bearer ' + creds.access_token,
}
for sheet in result['sheets']:
params = {
'id': SPREADSHEET_ID,
'format': 'csv',
'gid': sheet['properties']['sheetId'],
}
queryParams = urllib.parse.urlencode(params)
urlParts = urlParts._replace(query=queryParams)
url = urllib.parse.urlunparse(urlParts)
response = requests.get(url, headers = headers)
filePath = '/tmp/foo-%s.csv' % (+ params['gid'])
with open(filePath, 'wb') as csvFile:
csvFile.write(response.content)
The exportLinks collection doesn't expose the CSV format as this will only export the first worksheet of a spreadsheet. If retrieving the first worksheet as a CSV is the behavior you are looking for, you can build the link manually and set the ?exportFormat= query parameter to ?exportFormat=csv.
Here's an implementation of Alain's suggestion that works for me:
downloadUrl = entry.get('exportLinks')['application/pdf']
# Strip "=pdf" and replace with "=csv"
downloadUrl = downloadUrl[:-4] + "=csv"
resp, content = drive_service._http.request(downloadUrl)
Not sure if it's what the OP needed, but in the new Google Sheets version it seems that it became a little hard to hot link a csv version of your spreadsheet.
In case you are interested in a Google apps script that will export all sheets in a spreadsheet to individual csv files (instead of downloading each one individually), Here you go:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "export as csv files", functionName: "saveAsCSV"}];
ss.addMenu("csv", csvMenuEntries);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
var folder = DocsList.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
}
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function convertRangeToCsvFile_(csvFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
Note: This script uses the DocsList.createFile() method, which is only available for Google Apps accounts.
If you need further explanation, go here: http://drzon.net/export-all-google-sheets-to-csv/
(Jul 2016) This question is phrased correctly, but in essence is a duplicate of another thread (Download a spreadsheet from Google Docs using Python). While some of the previous answers to this question below may still work (although answers are in JS/Apps Script not Python), a new Drive API version (v3) and new Sheets API version (v4) make them slightly outdated although the previous versions of both have not been deprecated (yet). Modern Google API access occurs using API keys or OAuth2 authorization, primarily with the Google APIs Client Libraries, including the one for Python.
To perform the task requested in/by the OP, you would perhaps query for specific Sheets to download, then perform the actual export(s) with the Drive API. Since this is likely a common operation, I wrote a blogpost sharing a code snippet that does this for you. If you wish to pursue exporting further, I've got another pair of posts along with a video that outlines how to upload files to and download files from Google Drive.
Note that there is also a Google Sheets API, but it's primarily for spreadsheet-oriented operations, i.e., inserting data, reading spreadsheet rows, cell formatting, creating charts, adding pivot tables, etc., not file-based requests like exporting where the Drive API is the correct one to use.
Note, as of April 2015 DocsList was depreciated, and has been replaced by DriveApp. Many of the DriveApp methods are identical to DocsList. So, in many cases, you can simply replace DocsList with DriveApp. So replace DocsList.createFile() with DriveApp.createFile()
How to update DocsList to DriveApp in my code