Did Google Sheets stop allowing json access? - json

I have an app that opens the json version of a spreadsheet that I've published to the web. I used the instructions on this website: https://www.freecodecamp.org/news/cjn-google-sheets-as-json-endpoint/
It's been working fine for a couple months, but today I realized that the url of my json file is no longer working since yesterday. It gives the message, "Sorry, unable to open the file at this time. Please check the address and try again." The regular link to view the spreadsheet as a webpage still works though.
Did Google drop support for this feature? Is there another way to get the data of a spreadsheet in json format through a URL? I started looking into the Google Developer API, but it was really confusing.

You are using the JSON Alt Type variant of the Google Data protocol. This protocol is dated and appears to no longer work reliably. The GData API Directory tells:
Google Spreadsheets Data API: GData version is still live. Replaced by the Google Sheets API v4.
Google Sheets API v4 is a modern RESTful interface that is typically used with a client library to handle authentication and batch processing of data requests. If you do not want to do a full-blown client implementation, David Kutcher offers the following v4 analog for the GData JSON Alt Type, using jQuery:
GData (old version, not recommended):
var url = 'https://spreadsheets.google.com/feeds/list/' +
spreadsheet_id + '/' + tab_ordinal + '/public/values?alt=json';
($.getJSON(url, 'callback=?')).success(function(data) {
// ...
};
V4 (new version, recommended):
var url = 'https://sheets.googleapis.com/v4/spreadsheets/' +
spreadsheet_id + '/values/' + tab_name +
'?alt=json&key=' + api_key;
($.getJSON(url, 'callback=?')).success(function(data) {
// ...
};
...where:
spreadsheet_id is the long string of letters and numbers in the address of the spreadsheet — it is the bit between /d/ and /edit
tab_ordinal is number of the sheet — the first sheet that appears in the tab bar is sheet number 1, the second one is 2, and so on
tab_name is the name of the sheet, i.e., the name you see in the tab bar at the bottom of the window when you have the spreadsheet open for editing
api_key is the API key you get from from Google Cloud Platform console
Note that the JSON output format differs between the two versions.
With the GData pattern, the spreadsheet needs to be shared as File > Share > Publish to the web.
With the V4 pattern, the spreadsheet needs to be shared as File > Share > Share with others > anyone with the link can view.

As of March 2022:
If you dont want to create a key you can use this URL format:
https://docs.google.com/spreadsheets/d/{spreadsheetId}/gviz/tq
which downloads a json.txt file of the format
google.visualization.Query.setResponse({json});
From that you would have to slice out the json
-OR --
Just configure a key as per the Official docs.
Go to Google Console and create a project (or use an existing one)
Goto Credenetials page and create a API Key
Include Sheets API from library
And Voila!
You can now get json using URL Format:
https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{sheetName}?alt=json&key={theKey}
Edit: The Sheet should be public and Anyone with link can view

Without jQuery ...
var url = 'https://docs.google.com/spreadsheets/d/'+id+'/gviz/tq?tqx=out:json&tq&gid='+gid;
with id of the spreadsheet and gid of the sheet
https://codepen.io/mikesteelson/pen/wvevppe
example :
var id = '______your_speadsheet_id________';
var gid = '0';
var url = 'https://docs.google.com/spreadsheets/d/'+id+'/gviz/tq?tqx=out:json&tq&gid='+gid;
fetch(url)
.then(response => response.text())
.then(data => document.getElementById("json").innerHTML=myItems(data.substring(47).slice(0, -2))
);
function myItems(jsonString){
var json = JSON.parse(jsonString);
var table = '<table><tr>'
json.table.cols.forEach(colonne => table += '<th>' + colonne.label + '</th>')
table += '</tr>'
json.table.rows.forEach(ligne => {
table += '<tr>'
ligne.c.forEach(cellule => {
try{var valeur = cellule.f ? cellule.f : cellule.v}
catch(e){var valeur = ''}
table += '<td>' + valeur + '</td>'
}
)
table += '</tr>'
}
)
table += '</table>'
return table
}

gdata is the older version of Sheets API and it's shut down. See Google's announcement here https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api

Related

Google Sheets Advanced Google Services URL Shortener 403 Error: Forbidden

I am trying to create a small application in in Google Sheets to sorten URLs on my personal google account. I am using the following code which I found here: Google Sheets Function to get a shortened URL (from Bit.ly or goo.gl etc.)
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Shorten")
.addItem("Go !!","rangeShort")
.addToUi()
}
function rangeShort() {
var range = SpreadsheetApp.getActiveRange(), data = range.getValues();
var output = [];
for(var i = 0, iLen = data.length; i < iLen; i++) {
//var url = UrlShortener.Url.insert({longUrl: data[i][0]});
var url = UrlShortener.Url.insert({longUrl: 'www.google.com'});
output.push([url.id]);
}
range.offset(0,1).setValues(output);
}
I created a new Google Cloud Project and enabled the URL shortener API in the project and on the Google sheet. The problem is that when I try and run the code I get an err on the line: var url = UrlShortener.Url.insert({longUrl: 'www.google.com'});
error 403, message:forbidden
when i try an execute the rangeShort() function. I have no idea how to fix this. Any ideas would be most appreciated! Thanks!
As it turns out, like Ruben mentioned, Google has moved away from their URL shortener. So after much research ans testing here is the solution:
Step 1
Migrate Google Cloud Project over to Firebase or create a new Firebase Project. See steps here
Step 2
Create a dummy project in order to create a base URL for the shortening. See this youtube video
Step 3
Get the Web API Key from your new Firebase Project (not the app you just created)
Step 4
Check the left side menu on the screen and navigate to Grow->Dynamic Links. You should see the new application you created and a URL at the top of the application. This will become the base of the new shortened URLs.
Step 5
Create the code in Google Apps Script inside the code builder from within Google Sheets. Here is the code that worked for me (I passed the url into this function) (This code is based on the answer found here):
function api_call(url){
var req='https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=[YOUR PROJECT WEB API KEY FROM STEP 3]';
var formData = {
"longDynamicLink": "[YOUR APPLICATION URL BASE FROM STEP 4]?link=" + url,
"suffix" : {
"option" : "UNGUESSABLE"
}
};
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(formData)
};
var response = UrlFetchApp.fetch(req, options);
var res=JSON.parse(response);
return res.shortLink;
}
Additional Information
Documentation on Creating Dynamic Links in Firebase
Documentation on using UrlFetchApp() in Google Apps Script
If the url shortener service was used in your project before March 30,2018
Instead of
www.google.com
use
https://www.google.com
Reference: https://developers.google.com/url-shortener/v1/url/insert
but if your project was created on or after March 30, 2018
From https://developers.google.com/url-shortener/v1/
Starting March 30, 2018, we will be turning down support for goo.gl URL shortener. Please see this blog post for detailed timelines and alternatives.
Just to be clear, please note, from the linked blog post:
For developers
Starting May 30, 2018, only projects that have accessed URL Shortener
APIs before today can create short links.
I can attest to #alutz's answer here with a small addition/correction to their code.
Use encodeURIcomponent() for the input url while assigning it to the Long Dynamic Link in case you have more than one custom parameters.
"longDynamicLink": "[YOUR APPLICATION URL BASE FROM STEP 4]?link=" + encodeURIcomponent(url),
This allowed me to pass in multiple arguments for my telegram bot like chat_id, text and parse_mode.

Google app scripts: email a spreadsheet as excel

How do you make an app script which attaches a spreadsheet as an excel file and emails it to a certain email address?
There are some older posts on Stackoverflow on how to do this however they seem to be outdated now and do not seem to work.
Thank you.
It looks like #Christiaan Westerbeek's answer is spot on but its been a year now since his post and I think there needs to be a bit of a modification in the script he has given above.
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
There is something wrong with this line of code, maybe that exportLinks has now depreciated. When I executed his code it gave an error to the following effect:
TypeError: Cannot read property "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" from undefined.
The workaround is as follows:
The URL in the above line of code is basically the "download as xlsx" URL that can be used to directly download the spreadsheet as an xlsx file that you get from File> Download as > Microsoft Excel (.xlsx)
This is the format:
https://docs.google.com/spreadsheets/d/<<<ID>>>/export?format=xlsx&id=<<<ID>>>
where <<>> should be replaced by the ID of your file.
Check here to easily understand how to extract the ID from the URL of your google sheet.
Here's an up-to-date and working version. One prerequisite for this Google Apps script to work is that the Drive API v2 Advanced Google Service must be enabled. Enable it in your Google Apps script via Resources -> Advanced Google Services... -> Drive API v2 -> on. Then, that window will tell you that you must also enabled this service in the Google Developers Console. Follow the link and enable the service there too! When you're done, just use this script.
/**
* Thanks to a few answers that helped me build this script
* Explaining the Advanced Drive Service must be enabled: http://stackoverflow.com/a/27281729/1385429
* Explaining how to convert to a blob: http://ctrlq.org/code/20009-convert-google-documents
* Explaining how to convert to zip and to send the email: http://ctrlq.org/code/19869-email-google-spreadsheets-pdf
* New way to set the url to download from by #tera
*/
function emailAsExcel(config) {
if (!config || !config.to || !config.subject || !config.body) {
throw new Error('Configure "to", "subject" and "body" in an object as the first parameter');
}
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = spreadsheet.getId()
var file = Drive.Files.get(spreadsheetId);
var url = 'https://docs.google.com/spreadsheets/d/'+spreadsheetId+'/export?format=xlsx';
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var fileName = (config.fileName || spreadsheet.getName()) + '.xlsx';
var blobs = [response.getBlob().setName(fileName)];
if (config.zip) {
blobs = [Utilities.zip(blobs).setName(fileName + '.zip')];
}
GmailApp.sendEmail(
config.to,
config.subject,
config.body,
{
attachments: blobs
}
);
}
Update: I updated the way to set the url to download from. Doing it through the file.exportLinks collection is not working anymore. Thanks to #tera for pointing that out in his answer.

Set Maps API key in Script Editor

As far as I understand, in order to track our quota usage, we need to provide our API key to the Google App Service on the service we are planning to use.
In my case I have a spreadsheet with Origin and Destination and a Custom function to calculate the distance between.
I ran into the problem of meeting the quota from invoking .getDirections():
Error: Service invoked too many times for one day: route. (line **).
Sample of the code:
function getDirections_(origin, destination) {
var directionFinder = Maps.newDirectionFinder();
directionFinder.setOrigin(origin);
directionFinder.setDestination(destination);
var directions = directionFinder.getDirections();
return directions;
}
So I read that if I assign the API Key to my project I should be able to see the usage and how close to the free quota I am.
In the script editor, I did enable all of the APIs under Resources menu/ Advanced Google Services. Then I went to the Google Developers Console and there
I did not see any record of how many times my custom function called the Google Maps API or any API usage.
Logically I think that in my script I need to set my google API Key so my scripts start to call the API under my user name and count the number of time I used certain API. I guess right now I am using the Google Maps API as anonymous and since the whole company is assigned with the same IP, so we exhaust the permitted numbers to call this function.
Bottom line please reply if you know a way to connect my simple Spreadsheet function to the Public API access Key I have.
Thank you,
Paul
I also have been eager to find this answer for a long time and am happy to say that I've found it. It looks like Google might have just made this available around Oct 14, 2015 based on the date this page was updated.
You can leverage the UrlFetchApp to add your API key. The link I posted above should help with obtaining that key.
function directionsAPI(origin, destination) {
var Your_API_KEY = "Put Your API Key Here";
var serviceUrl = "https://maps.googleapis.com/maps/api/directions/json?origin="+origin+"&destination="+destination+
"&mode="+Maps.DirectionFinder.Mode.DRIVING+"&alternatives="+Boolean(1)+"&key="+Your_API_KEY;
var options={
muteHttpExceptions:true,
contentType: "application/json",
};
var response=UrlFetchApp.fetch(serviceUrl, options);
if(response.getResponseCode() == 200) {
var directions = JSON.parse(response.getContentText());
if (directions !== null){
return directions;
}
}
return false;
}
So walking through the code... first put in your API key. Then choose your parameters in the var serviceUrl. I've thrown in additional parameters (mode and alternatives) to show how you can add them. If you don't want them, remove them.
With UrlFetch you can add options. I've used muteHttpExceptions so that the fetch will not throw an exception if the response code indicates failure. That way we can choose a return type for the function instead of it throwing an exception. I'm using JSON for the content type so we can use the same format to send and retrieve the request. A response code of 200 means success, so directions will then parse and act like the object that getDirections() would return. The function will return false if the UrlFetch was not successful (a different response code) or if the object is null.
You will be able to see the queries in real time in your developer console when you look in the Google Maps Directions API. Be sure that billing is enabled, and you will be charged once you exceed the quotas.
1.) I added an API key from my console dashboard. Remember to select the correct project you are working on. https://console.developers.google.com/apis/credentials?project=
2.) In my Project (Scripts Editor) I setAuthentication to Maps using the API key and the Client ID from the console. I have included the script below:
function getDrivingDirections(startLoc, wayPoint, endLoc){
var key = "Your_API_Key";
var clientID = "Your_Client_ID";
Maps.setAuthentication(clientID, key);
var directions = Maps.newDirectionFinder()
.setOrigin(startLoc)
.addWaypoint(wayPoint)
.setDestination(endLoc)
.setMode(Maps.DirectionFinder.Mode.DRIVING)
.getDirections();
} return directions;
https://developers.google.com/apps-script/reference/maps/maps#setAuthentication(String,String)
As of 7/13/2017, I was able to get the API to function by enabling the Sheets API in both the "Advanced Google Services" menu (images 1 and 2), and in the Google Developer Console. If you're logged into Google Sheets with the same email address, no fetch function should be necessary.
[In the Resources menu, select Advanced Google Services.][1]
[In Advanced Google Services, make sure the Google Sheets API is turned on.][2]
[1]:
[2]:
Thank goodness for JP Carlin! Thank you for your answer above. JP's answer also explains his code. Just to share, without a code explanation (just go look above for JP Carlin's explanation), below is my version. You will see that I also have the departure_time parameter so that I will get distance and driving-minutes for a specific date-time. I also added a call to Log errors (to view under "View/Logs"):
Note: Google support told me that using your API-key for Google Maps (e.g. with "Directions API") with Google Sheets is not supported. The code below works, but is an unsupported work-around. As of 11/4/2018, Google has an internal ticket request to add support for Google Maps APIs within Google Sheets, but no timeline for adding that feature.
/********************************************************************************
* directionsAPI: get distance and time taking traffic into account, from Google Maps API
********************************************************************************/
function directionsAPI(origin, destination, customDate) {
var Your_API_KEY = "<put your APK key here between the quotes>";
var serviceUrl = "https://maps.googleapis.com/maps/api/directions/json?origin="+origin+"&destination="+destination+"&departure_time="+customDate.getTime()+"&mode="+Maps.DirectionFinder.Mode.DRIVING+"&key="+Your_API_KEY;
var options={
muteHttpExceptions:true,
contentType: "application/json",
};
var response=UrlFetchApp.fetch(serviceUrl, options);
if(response.getResponseCode() == 200) {
var directions = JSON.parse(response.getContentText());
if (directions !== null){
return directions;
}
}
Logger.log("Error: " + response.getResponseCode() + " From: " + origin + ", To: " + destination + ", customDate: " + customDate + ", customDate.getTime(): " + customDate.getTime() );
return false;
}

Is it possible to impersonate domain's users with Google Drive API using Google Apps Script?

I am a head of studies and school administrator of our Google Apps for Education.
I used Google Apps Script for a lot of applications (control of absences, sending emails, automatic reporting, ScriptDb databases and more) using gas services. It's fantastic.
Basically I need to create a folder structure (years, courses, teachers, ...) within the Google Drive of students.
With Google Apps Script services I can do it easily but then the folders belong to the creator (administrator) and I think then users spend the administrator storage quota. This does not interest me.
(Yes, I can make an application to be executed by the users and create the structure in its Google Drive, but I'd rather do it in an automated manner and without intervention)
To create this documents (and folders) in Google Drive users (teachers, students, ...) have adapted the code provided by Waqar Ahmad in this response [ Add an writer to a spreadsheet ... ]
That allows me to take possession of documents of other users to make updates using the Google Document List API (Google Apps administrative access to impersonate a user of the domain) and also have adapted to create folders and files on other Google Drive users. It works perfectly. I mention here:
How to add a Google Drive folder ...
But now, the version 3 of the Google Documents List AP, has been officially deprecated and encourage us to work with the Google API Drive.
I tried to do the same with this new Google API. Has anyone managed to do this? Is it possible? I have no idea where to start!
Thank you.
Sergi
Updated:
This is the code i'm working but I get an "invalid request" error:
(...)
var user = e.parameter.TB_email // I get user from a TextBox
//https://developers.google.com/accounts/docs/OAuth2ServiceAccount
//{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}
//{Base64url encoded header}
var header = '{"alg":"RS256","typ":"JWT"}'
var header_b64e = Utilities.base64Encode(header)
//{Base64url encoded claim set}
var t_ara = Math.round((new Date().getTime())/1000) // now
var t_fins = t_ara + 3600 // t + 3600 sec
var claim_set = '{"iss":"1111111111-xxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com",'+
'"prn":"' + user + '",' +
'"scope":"https://www.googleapis.com/auth/prediction",'+
'"aud":"https://accounts.google.com/o/oauth2/token",'+
'"exp":'+t_fins+','+
'"iat":'+t_ara+'}'
// where '1111111111-xxxxxxxxxxx... is my CLIENT-ID (API Access -> Service Account)
var claim_set_b64e = Utilities.base64Encode(claim_set)
claim_set_b64e = claim_set_b64e.replace(/=/g,'')
var to_sign = header_b64e + '.' + claim_set_b64e
// [signature bytes] ??? // password 'isnotasecret???'
var key_secret = DocsList.getFileById('0Biiiiiiiiii-XXXXXXXXXXX').getBlob().getBytes()
// where '0Biiiiiiiiii-XXXXXXXXXXX'... is my p12 file (key_secret) uploaded to GDRive
// I don't know if this is correct !!!
var sign = Utilities.base64Encode(Utilities.computeHmacSha256Signature(to_sign, key_secret))
var JWT_signed = to_sign + '.' + sign
JWT_signed = JWT_signed.replace(/=/g,'')
// Token Request /////////////////////////////////////////////////////////////
var url = 'https://accounts.google.com/o/oauth2/token'
//var url = 'https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken' ???
//var url = 'https:' + '%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken' ???
var parameters = {
"method" : "POST",
"payload" : '"' + 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=' + JWT_signed + '"',
"contentType" : "application/x-www-form-urlencoded"
}
var content = UrlFetchApp.fetch(url,parameters) //.getContentText()
// Token Request end ////////////////////////////////////////////////////////
And I get an "Invalid Request" and not a JSON with the token
The 2 first parts ( header & claim set ) are OK. The result are equal to the result of Google OAuth page.
I don't know if the signature part are correct or if the error is in the token request.
The issue with your example above is that it it's computing the signature with hmacsha256. You need to use rsasha256. There are two service account libraries for apps script right now. One that I put together is:
https://gist.github.com/Spencer-Easton/f8dad65932bff4c9efc1
The issue with both libraries is they are derived from jsrsa which runs very slow on the server side.

Using the google drive API to download a spreadsheet in csv format

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