When trying to use the IMPORTDATA function for this file:
https://www.kaggle.com/stefanoleone992/fifa-20-complete-player-dataset#players_20.csv
An unexpected error occurs that says it is impossible to import data into the spreadsheet. Is there any other way that I can bring this data to my spreadsheet?
This data would be very important to the work I'm doing. It would save me from almost 3 months of work to be able to type and copy everything and then filtering according to my need.
It would be very important to be able to import at least the simple info of all players, but do not necessarily have to import all columns of info from each player. The amount of columns can import is already perfect.
I would be grateful if there was any way.
You want to download a CSV file of players_20.csv from https://www.kaggle.com/stefanoleone992/fifa-20-complete-player-dataset and put the CSV data to the Spreadsheet.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several answers.
Issue and workaround:
Unfortunately, the CSV data cannot be directly downloaded from the URL of https://www.kaggle.com/stefanoleone992/fifa-20-complete-player-dataset#players_20.csv. In order to download the CSV file, it is required to login to kaggle. As other pattern, you can also download it using API. In this answer, in order to download the CSV file, I used Kaggle's public API.
Usage:
1. Retrieve token file:
Before you use the script, please register an account to https://www.kaggle.com, and retrieve the token file. About how to retrieve the token file, you can see the official document.
In order to use the Kaggle’s public API, you must first authenticate using an API token. From the site header, click on your user profile picture, then on “My Account” from the dropdown menu. This will take you to your account settings at https://www.kaggle.com/account. Scroll down to the section of the page labelled API:
To create a new token, click on the “Create New API Token” button. This will download a fresh authentication token onto your machine.
In this script, the token object in the downloaded token file is used.
2. Run script:
Please copy and paste the following script to the container-bound script of Spreadsheet. And please set the variavles of csvFilename, path and tokenObject. In your case, I have already set csvFilename and path. So please set only your token object.
function myFunction() {
var csvFilename = "players_20.csv"; // Please set the CSV filename.
var path = "stefanoleone992/fifa-20-complete-player-dataset"; // Please set the path.
var tokenObject = {"username":"###","key":"###"}; // <--- Please set the token object.
var baseUrl = "https://www.kaggle.com/api/v1/datasets/download/";
var url = baseUrl + path;
var params = {headers: {Authorization: "Basic " + Utilities.base64Encode(tokenObject.username + ':' + tokenObject.key)}};
var blob = UrlFetchApp.fetch(url, params).getBlob();
var csvBlob = Utilities.unzip(blob).filter(function(b) {return b.getName() == csvFilename});
if (csvBlob.length == 1) {
var csvData = Utilities.parseCsv(csvBlob[0].getDataAsString());
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
} else {
throw new Error("CSV file of " + csvFilename + " was not found.");
}
}
Flow:
The flow of this script is as follows.
When the script is run, the kaggle command of kaggle datasets download -d stefanoleone992/fifa-20-complete-player-dataset is run with Google Apps Script. By this, the ZIP file is downloaded.
Retrieve the CSV file of csvFilename from the downloaded ZIP file.
Parse the CSV data from the CSV file.
Put the CSV data to the active sheet.
In this script, all data is processed with the blob. So the file is not created.
Note:
It seems that the CSV data is large. So please wait until the script is finished.
In my environment, I spent for about 150 seconds until the CSV data is put to the Spreadsheet.
The CSV data of players_20.csv has 18279 rows and 104 columns.
If an error occurs at Utilities.unzip(blob), please test to modify from var blob = UrlFetchApp.fetch(url, params).getBlob() to var blob = UrlFetchApp.fetch(url, params).getBlob().setContentTypeFromExtension().
References:
Authentication of Kaggle's public API
kaggle-api
If I misunderstood your question and this was not the direction you want, I apologize.
Added 1:
If you want to select the columns you want to put, please modify above sample script as follows.
From:
var csvData = Utilities.parseCsv(csvBlob[0].getDataAsString());
var sheet = SpreadsheetApp.getActiveSheet();
To:
var csvData = Utilities.parseCsv(csvBlob[0].getDataAsString());
var needColumns = [1, 2, 3];
csvData = csvData.map(function(row) {return needColumns.map(function(col) {return row[col]})});
var sheet = SpreadsheetApp.getActiveSheet();
In above modification, as the test case, the columns of 1, 2 and 3 are put to the Spreadsheet.
Added 2:
From the result of benchmark for putting CSV data to Spreadsheet, for example, how about using Sheets API for putting CSV data? For this, please modify above sample script as follows. Before you run the script, please enable Sheets API at Advanced Google services.
From:
var csvData = Utilities.parseCsv(csvBlob[0].getDataAsString());
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
To:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var resource = {requests: [{pasteData: {data: csvBlob[0].getDataAsString(), coordinate: {sheetId: sheet.getSheetId()}, delimiter: ","}}]};
Sheets.Spreadsheets.batchUpdate(resource, ss.getId());
In this case, I spent for about 50 seconds until the CSV data is put to the Spreadsheet.
Reference:
Benchmark: Importing CSV Data to Spreadsheet using Google Apps Script
Advanced Google services
Related
I have a Google Sheet spreadsheet containing personal data I collect from people who subscribe to my association. They have to complete an online form and sign it. The data is then sent to the spreadsheet and the signature is imported as a PNG in-cell-image.
I need to extract all the PNG signatures and assign them the specific ID found in the same row so I can later match the signature with the correct personal data when generating a PDF form with another script.
ID
Signature
1a2b3c4d
image.png
5e6f7g7h
image.png
I am currently using the following code I found online. It saves all the images to a folder as PNG files but it assigns names like "image-1", "image-2" in a random order.
Here is the code:
function myFunction() {
const spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
const url = "https://docs.google.com/spreadsheets/export?exportFormat=xlsx&id=" + spreadsheetId;
const blob = UrlFetchApp.fetch(url, {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}}).getBlob().setContentType(MimeType.ZIP);
const xlsx = Utilities.unzip(blob);
xlsx.forEach(b => {
const name = b.getName().match(/xl\/media\/(.+)/);
if (name) DriveApp.getFolderById("1mdJbbG_0aF8wjEIuVPsMr9jV31wPINRk").createFile(b.setName(name[1]));
});
}
How can I edit the code to name each file with the corresponding ID?
Thanks a lot!
EDIT:
I collect data from an online form which is displayed in the image below.
Online Form
When clicking on the signature field, a signature pad opens and allows the user to sign.
Signature Pad
Collected data are then sent to the following spreadsheet stored in Google Drive.
Spreadsheet
The script which sends data from the form to the spreadsheet should be the following
function submit(data) {
data = JSON.parse(data)
const headers = SETTINGS.HEADERS.map(({value}) => value)
const id = Utilities.getUuid()
const signatures = []
const values = SETTINGS.HEADERS.map(({key}, index) => {
if (key === "id") return id
if (key === "timestamp") return new Date()
if (!key in data) return null
if (Array.isArray(data[key])) return data[key].join(",")
if (data[key].startsWith("data:image")) {
signatures.push(index)
return SpreadsheetApp.newCellImage().setSourceUrl(data[key]).build().toBuilder()
}
return data[key]
})
const ws = SpreadsheetApp.getActive().getSheetByName(SETTINGS.SHEET_NAME.RESPONSES) || SpreadsheetApp.getActive().insertSheet(SETTINGS.SHEET_NAME.RESPONSES)
ws.getRange(1,1, 1, headers.length).setValues([headers])
const lastRow = ws.getLastRow()
ws.getRange(lastRow + 1, 1, 1, values.length).setValues([values])
signatures.forEach(index => {
ws.getRange(lastRow + 1, index + 1).setValue(values[index])
})
return JSON.stringify({success: true, message: `Grazie per la tua richiesta di iscrizione! ID: ${id}`})
}
The need is to rename the signature image with the submission ID.
In that way, in theory, when I run Tanaike's script to extract the images from the spreadsheet, they should be named with the ID of the corresponding form submission.
As of now, when I run Tanaike's script I get the following output.
Tanaike's script output
Thanks a lot!
I believe your goal is as follows.
You want to export the images of column "O" in Google Spreadsheet. In this case, you want to use the values of column "B" as the filename.
The image is put into the cells as CellImage.
Modification points:
Using XLSX data converted from Spreadsheet, when the image files are directly retrieved from XLSX data, unfortunately, the images cannot correspond to each cell coordinate. I thought that this is the reason of your issue. In this case, it is required to parse the XLSX data. But, I thought that in this case, the script might be a bit complicated. So, in order to retrieve the image data from the XLSX with the cell coordinate, I have created a Google Apps Script library. Ref
In this answer, I would like to propose a sample script using the library.
Usage:
1. Install Google Apps Script library.
Please install DocsServiceApp Google Apps Script library. You can see how to install it at here.
2. Sample script.
Please copy and paste the following script to the script editor of Spreadsheet. And, please set the variables of folderId and sheetName.
function myFunction() {
const folderId = "###"; // Please set folder ID you want to put the created files.
const sheetName = "Sheet1"; // Please set your sheet name.
// Retrieve image data.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const res = DocsServiceApp.openBySpreadsheetId(ss.getId()).getSheetByName(sheetName).getImages();
// Retrieve IDs from from column "B"
const folder = DriveApp.getFolderById(folderId);
const sheet = ss.getSheetByName(sheetName);
const values = sheet.getRange("B1:B" + sheet.getLastRow()).getValues();
// Create files.
res.forEach(({ range, image }) =>
folder.createFile(image.blob.setName(`${values[range.row - 1][0]}.png` || image.blob.getName()))
);
}
When this script is run, the image data is retrieved and created as the image file using the filename retrieved from column "B".
Note:
In this sample script, from your provided sample image, it supposes that the image data and the filename are put in the columns "O" and "B", respectively. Please be careful about this.
Reference:
DocsServiceApp
I want to download xlsx file from my Google Sheet via google script.
But the file I downloaded cannot be opened correctly.
function doGet(e)
{
//Get My Spreadsheet
var ss = SpreadsheetApp.openById("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
//Create URL to Export as xlsx
var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + ss.getId() + "&exportFormat=xlsx";
//Get the file
var file = UrlFetchApp.fetch(url);
//Get the blob
var blob = file.getBlob();
// sets the file extension
blob.setName(ss.getName() + ".xlsx");
return ContentService.createTextOutput(file.getContentText()).downloadAsFile("Test.xlsx");
}
Unfortunately, it seems that in the current stage, downloadAsFile(filename) can be used for the text file. I thought that this is the reason of your issue.
In your situation, it is required to use a workaround. This workaround uses an HTML service. When this is reflected in your script, it becomes as follows.
Modified script:
function doGet(e) {
var spreadsheetId = "###"; // Please set your Spreadsheet ID.
var url = "https://docs.google.com/feeds/download/spreadsheets/Export?key=" + spreadsheetId + "&exportFormat=xlsx";
var file = UrlFetchApp.fetch(url);
var blob = file.getBlob();
var html = HtmlService.createTemplate('<body></body><script>const a=document.createElement("a");document.body.appendChild(a),a.download="<?= filename ?>",a.href="<?= data ?>",a.click();</script>');
html.data = "data:application/pdf;base64," + Utilities.base64Encode(blob.getBytes());
html.filename = ss.getName() + ".xlsx";
return html.evaluate();
}
When this web apps is accessed after this script was reflected in the Web Apps, the spreadsheet of spreadsheetId is converted to XLSX data and it is automatically downloaded.
Note:
In your script, it seems that Web Apps is used. In this case, when you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
downloadAsFile(filename)
Web Apps
Taking advantage of Web Apps with Google Apps Script
I have a Google Sheet with content in say Col 1. One sentence in each row. I am looking for a script which can save the Col 1 as 'epub' with each sentence (in row) as a new page.
I believe your current situation and your goal as follows.
In your Spreadsheet, there are the sentences in each row of the column "A".
You want to retrieve a value from a cell of column "A" and convert it as a file of EPUB on your Google Drive.
You want to achieve this using Google Apps Script.
In this case, I would like to propose the following flow.
Retrieve the values from the column "A" of the Spreadsheet.
Create Google Document as the temporal file.
Copy the values to Google Document.
Export Google Document as EPUB of application/epub+zip and save it as a file on Google Drive.
Remove the temporal file.
When above flow is reflected to the script, it becomes as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet you want to use. And, please run myFunction. By this, the values are retrieved from the cells "A1:A" and create EPUB files using the values of each row.
function myFunction() {
const sheetName = "Sheet1"; // Please set the sheet name.
const folderId = "root"; // Please set the folder ID you want to export the EPUB files. In the case of "root", the files are created to the root folder.
// 1. Retrieve the values from the column "A" of the Spreadsheet.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const startRow = 1;
const endRow = sheet.getLastRow();
const values = sheet.getRange(`A${startRow}:A${endRow}`).getDisplayValues();
// 2. Create Google Document as the temporal file.
const tempDoc = DocumentApp.create("temp");
const id = tempDoc.getId();
const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id;
const params = {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}};
const folder = DriveApp.getFolderById(folderId || "root");
const ids = values.map(([a], i) => {
// 3. Copy the values to Google Document.
const filename = `rowNumber${i + 1}`;
const doc = DocumentApp.openById(id).setName(filename);
doc.getBody().clear().appendParagraph(a);
doc.saveAndClose();
// 4. Export Google Document as EPUB of `application/epub+zip` and save it as a file on Google Drive.
const blob = UrlFetchApp.fetch(url, params).getBlob().setName(`${filename}.epub`);
return folder.createFile(blob).getId();
});
console.log(ids); // Here, you can see the file IDs of the created EPUB files at the log.
// 5. Remove the temporal file.
DriveApp.getFileById(id).setTrashed(true);
}
In this sample script, the filename is rowNumber${i + 1}. So, the created filename is like rowNumber1.epub, rowNumber2.epub. If you want to change this, please modify above script.
The endpoint of const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id; is from exportLinks of the method of "Files: get" of Drive API. Ref
Note:
In this case, when a lot of rows are existing in your Spreadsheet, the process time might be over the maximum execution time of 6 minutes. Please be careful this. If the process time is over the maximum execution time, please modify the values of startRow and endRow.
If an error related to Drive API occurs, please enable Drive API at Advanced Google servicves.
If you want to convert the values of the column "A" as one EPUB file, you can also use the following script.
function myFunction2() {
const sheetName = "Sheet1";
const folderId = "root"; // Please set the folder ID you want to export the EPUB files. In the case of "root", the files are created to the root folder.
const filename = `sampleFile`; // Please set the output filename.
// 1. Retrieve the values from the column "A" of the Spreadsheet.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const startRow = 1;
const endRow = sheet.getLastRow();
const values = sheet.getRange(`A${startRow}:A${endRow}`).getDisplayValues();
// 2. Create Google Document as the temporal file.
const tempDoc = DocumentApp.create(filename);
// 3. Copy the values to Google Document.
tempDoc.getBody().clear().appendParagraph(values.flat().join("\n"));
tempDoc.saveAndClose();
const id = tempDoc.getId();
// 4. Export Google Document as EPUB of `application/epub+zip` and save it as a file on Google Drive.
const url = "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=epub&id=" + id;
const params = {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}};
const folder = DriveApp.getFolderById(folderId || "root");
const blob = UrlFetchApp.fetch(url, params).getBlob().setName(`${filename}.epub`);
const createdFileId = folder.createFile(blob).getId();
console.log(createdFileId); // Here, you can see the file ID of the created EPUB file at the log.
// 5. Remove the temporal file.
DriveApp.getFileById(id).setTrashed(true);
}
References:
Spreadsheet Service
Class UrlFetchApp
Drive Service
You need to enable Advanced Drive API
function makeEPUB() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const rg = sh.getRange(1,1,sh.getLastRow(),1);
const vs = rg.getDisplayValues().flat();//get rows
const document = DocumentApp.create('mydoc');//creat doc
let body = document.getBody();
vs.forEach(s =>{body.appendParagraph(s);body.appendPageBreak();});//append sentences and page breaks
document.saveAndClose();
let exportLink = Drive.Files.get(document.getId()).exportLinks["application/epub+zip"];
let response = UrlFetchApp.fetch(exportLink, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
let file = DriveApp.createFile(response.getBlob());
file.setName(document.getName() + ".epub");
}
Mostly Copied from Amit Agarwal
Don't know if it works. Have no way that I know of to test it.
I'm trying to sending an email from google app script with google sheet file.
For now I can send csv file with multiple file like:
MailApp.sendEmail(
emailList,
fileName,
'content',
{
attachments: list_attach,
name: 'Britag Support'
});
with list_attach same
[{
fileName: 'fileName1',
content: csvTextContent1,
mimeType:"application//csv"
}, {
fileName: 'fileName2',
content: csvTextContent2,
mimeType:"application//csv"
}]
the csvTextContent is a string like:
A,B,C\n1,2,3\n4,5,6\n...
It's create 2 file attach to email.
Now I want to join 2 above file to one excel file with 2 sheets. How can I do it? Please help me. thank you.
You want to convert 2 CSV files to one Excel file and you want to send an email by including the converted Excel file as an attachment file.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
The flow of this sample script is as follows.
Retrieve the CSV files from the array object of list_attach.
Create new Spreadsheet as a temporal.
Put the CSV data to the temporal Spreadsheet by parsing the CSV data.
Export the temporal Spreadsheet as the blob of Excel format.
Delete the temporal Spreadsheet. In this case, that is moved to the trash box.
Send an email including the exported Excel data.
Modified script:
When your script is modified, please modify as follows.
From:
MailApp.sendEmail(
emailList,
fileName,
'content',
{
attachments: list_attach,
name: 'Britag Support'
});
To:
// --- I added blow script
var tempSpreadsheeet = SpreadsheetApp.create("temp");
for (var i = 0; i < list_attach.length; i++) {
var obj = list_attach[i];
var values = Utilities.parseCsv(obj.content);
var sheet = i == 0 ? tempSpreadsheeet.getSheets()[0].setName(obj.fileName) : tempSpreadsheeet.insertSheet().setName(obj.fileName);
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
SpreadsheetApp.flush();
var tempId = tempSpreadsheeet.getId();
var url = "https://docs.google.com/spreadsheets/export?exportFormat=xlsx&id=" + tempId;
var blob = UrlFetchApp.fetch(url, {headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()}}).getBlob();
blob.setName("sampleFilename.xlsx");
list_attach = [blob];
DriveApp.getFileById(tempId).setTrashed(true);
// ---
MailApp.sendEmail(
emailList,
fileName,
'content',
{
attachments: list_attach,
name: 'Britag Support'
});
Note:
In above modified script, it supposes the following points.
csvTextContent1 and csvTextContent2 are the CSV data of the string type.
The numbers of all columns of CSV data are the same.
If above points are different from your actual data, can you provide the sample values of csvTextContent1 and csvTextContent2? By this, I would like to modify it.
References:
create(name)
parseCsv()
Files: export
setTrashed()
If I misunderstood your question and this was not the direction you want, I apologize.
I am trying to fetch a zip from a URL and import it automatically into a Google Spreadsheet.
The zip contains one file of CSV data.
I know I can import the CSV data into a Google Spreadsheet but I would like to be able to cut out the step of me having to download the zip and extract the file first before uploading it into a Google Spreadsheet.
So my queries, is it possible to import a zipped CSV file from a URL directly into a Google Spreadsheet? If not, how would this be done with a Google Apps Script?
To answer your question, no, you cannot directly import a Zip file containing a CSV directly into a spreadsheet. To answer your second question:
This question is kind of broad and needs to be broken down into three bits.
Retrieving the Zip from the URL
Extracting the CSV from the Zip
Inserting the CSV into your sheet
I'll briefly cover each of these three areas to get you going in the right direction, I am not going to write out a full fledged solution for you. I provide some code examples to make it easier for you to get going, this is not meant to be an end-to-end solution.
Retrieving the Zip from the URL
You can do this with the URLFetchApp Service.
Something like:
var urlData = UrlFetchApp.fetch(link);
var zipBlob = urlData.getBlob();
var files = Utilities.unzip(blob);
Extracting the CSV from the Zip
You need to get the contents of the ZIP file, find the CSV file in the ZIP, then parse it as a CSV into an array . In my example I use regex to escape the CSV as the Apps Script CSV parser is buggy.
function GetCSVFromZip(zipBlob){
var files = Utilities.unzip(zipBlob);
var csvAttachment = FindBlobByName(files, 'myPartialName');
if(csvAttachment !== -1){
var dataString = csvAttachment.getDataAsString();
var escapedString = dataString.replace(/(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]\r\n(?:\\[\s\S][^'\\]\r\n)*')/g, '\r\n'); //http://stackoverflow.com/a/29452781/3547347
var csv = Utilities.parseCsv(escapedString);
}
}
//Finds a blob by a partial name match, assumes no multiple matches
function FindBlobByName(blob, name){
for(var i = 0; i < blob.length; i++){
var blobName = blob[i].getName();
var regex = new RegExp(name, 'i');
var result = blobName.match(regex);
if(result){
return blob[i];
}
}
return -1;
}
Inserting the CSV into your sheet
You need to use the SpreadsheetApp Service for this. Get your spreadsheet, get a data range, and set it's values to your CSV array. Something along these lines:
var sheet = SpreadsheetApp.openById(id).getSheetByName(name);
var range = sheet.getRange(1, 1, csv.length, csv[0].length);
range.setValues(csv);
Using Douglas's answer, I managed to simplify it and read the zip from the link directly to spreadsheets. Here is my code:
function testzip(){
var url = "url goes here"
var zipblob = UrlFetchApp.fetch(url).getBlob();
var unzipblob = Utilities.unzip(zipblob);
var unzipstr=unzipblob[0].getDataAsString();
var csv = Utilities.parseCsv(unzipstr);
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
ss.getRange(1, 1, csv.length, csv[0].length).setValues(csv);
}
Heading