Google Script UrlFetchApp.fetch returns a 404 eventhough the page exist - google-apps-script

I am sending automated report with Google spreadsheet and Google script.
So far it was working perfectly. But somehow when I try to create a new report to be emailed, the function "UrlFetchApp.fetch" return a 404. The same situation happened when I tried copying the old report.
The line with "UrlFetchApp.fetch" give me this error:
Request failed for https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf returned code 404. Truncated server response
It seems that I am not the only one having the issue but I cannot find any solution to it.
Here is the code:
function emailSpreadsheetAsCSV() {
var ss = SpreadsheetApp.openById("1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8");
var url = ss.getUrl();
url = url.replace(/edit$/,'');
var token = ScriptApp.getOAuthToken();
var sheets = ss.getSheets();
//make an empty array to hold your fetched blobs
var blobs = [];
for (var i=0; i<sheets.length; i++) {
var response = UrlFetchApp.fetch("https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf", {
headers: {
'Authorization': 'Bearer ' + token
},
'muteHttpExceptions': false
});
//convert the response to a blob and store in our array
blobs[i] = response.getBlob().setName(sheets[i].getName() + '.csv');
}
//create new blob that is a zip file containing our blob array
var zipBlob = Utilities.zip(blobs).setName(ss.getName() + '.zip');
return blobs[0];
}
Thanks a lot for your help.
Aymeric.

I've gotten this problem too and after some research, Spence Easton (question 34573295) solved my issue. I simply added this bogus call to drive so access is granted, and so the script can now get to your file.
Add this near the top before trying to grab the url:
var bogus = DriveApp.getRootFolder();
Now it runs fine with no 404 errors.

Remove the headers from the request:
var response = UrlFetchApp.fetch("https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf", {
'muteHttpExceptions': false
});
Check if it works for you.

You use the "pub" url so are you sure the spreadsheet is published on the web ? If you get a 404 it means the page is not published.
If file is published the bearer is not necessary as it is public now.
After I don't really understand your code because you iterate all the sheets of your file
for (var i=0; i<sheets.length; i++)
but the param "gid" (pub?gid=195635557&single=true&output=pdf) for the url in your urlfetch is fixed ?
Second point you get the file as pdf and after you create a csv ?
Why not get the file as csv directly : https://docs.google.com/spreadsheets/export?id=TheIdOfTheFile&exportFormat=csv
By adapting this code you can get the csv directly, see : https://stackoverflow.com/a/28503601/3556215
Take care you will get the first page and not others.
Stéphane

Try with:
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(res.getContentText());

Related

Fetch file from external URL and upload to Google Drive using Apps Script

I'm not sure if this is even possible. I'm trying to fetch file that being uploaded to formfacade server via the add-on in google form. I'm using it to allow other non-gmail users to upload file without having to sign-in.
I referred to answer from Mogsdad and dheeraj raj in
Can I download file from URL link generated by google apps script to use UrlFetchApp to meet this objective. Below are my codes:
Method 1 :
function UrlFile2gdrive() {
var sheet=SpreadsheetApp.getActiveSheet();
var lrow=sheet.getLastRow();
//var fileURL=sheet.getRange(lrow,2).getValue();
var fileURL='https://formfacade.com/uploaded/1FAIpQLSfscYq_sbYcT2P3Sj3AvSD2zYKalIM0SKdPTESf1wE9Rq8qew/'
+'97dc1ee0-f212-11ea-95c3-bdb6c5ab13b3/2124651919/A%20Sample%20PDF.pdf'
var params = {method:"GET",headers:{"authorization":"Bearer "+ ScriptApp.getOAuthToken()}};
var response=UrlFetchApp.fetch(fileURL,params);
Logger.log(response.getContentText());
var fileBlob=response.getBlob();
var folder='0B2b-M7h6xF-Mflk3dGswano2TnJ3dGlmZG8wOUREMFg4blM5SHBuM3lqYmdPOThZSTBTSWs'
var filename=fileURL.split("/").pop();
//var filename=fileURL.split("%2F").pop();
var file=decodeURIComponent(filename);
Logger.log("filename : "+file);
var newfile=DriveApp.getFolderById(folder).createFile(fileBlob.setName(file));
//var newfile=DriveApp.getFolderById(folder).createFile(response.setName(filename));
}
Method 2
//api-key : AIzaSyCcbdBCI-Kgcz3tE1N4paeF9a-vdi3Uzz8
//Declare function
function URL2gdriveWithPswd() {
//Getting url,existing name and new name for image from the sheet in
//variable url, name and new_name respectively
var sh = SpreadsheetApp.getActiveSheet();
var row = sh.getLastRow();
Logger.log(row);
//for (var i = 2; i <= row; i++) {
/*var url = sh.getRange(i, 2).getValue();
Logger.log(url);
var name = sh.getRange(i, 3).getValue();
var new_name = sh.getRange(i, 4).getValue();*/
var url = sh.getRange(row, 2).getValue();
Logger.log(url);
var filenm=url.split("/").pop();
var new_name=decodeURIComponent(filenm);
var name = sh.getRange(row, 3).getValue();
//var new_name = sh.getRange(row, 4).getValue();
//Creating authentication token for downloading image, it may not be //required if image can be downloaded without login into
var user = "dtestsys#gmail.com";
var password = "1851235656";
var headers = {
"Accept": "application/xml",
"Content-Type": "application/xml",
"Authorization": "Basic " + Utilities.base64Encode(user + ":" + password)
};
//defining method to download file
var options = {
"method": "get",
"headers": headers
};
//Getting folder name where to store downloaded image
var folders = DriveApp.getFoldersByName('File Uploader (File responses)');
while (folders.hasNext()) {
var folder = folders.next();
Logger.log(folder.getName());
}
//Getting response on hit of url using downloading method defined //earlier storing in Blob
var response = UrlFetchApp.fetch(url, options).getBlob();
//Creating image in folder defined with response in blob and logging same file //in log to check, if required
var file = folder.createFile(response);
Logger.log(file);
//renaming image
var images = folder.getFiles();
while (images.hasNext()) {
var image = images.next();
file.setName(new_name);
Logger.log("imagename : "+image.getName());
}
//}
}
However, both methods managed to get a file into my gdrive but the content consists of the html codes only (https://drive.google.com/file/d/1NYQoMmCQEoP3z6L8niq1mpvIx7xl83zu/view?usp=sharing), which I think the URL passed in google response sheet is just a "mask". I noticed that inside the file has some lines that mentioned api-key and code (next to user email address). Is it possible to achieve my objective? Are those api-key and code would be useful to get authorized to access the file and download it in gdrive?
I rechecked.The link produced and passed into my google sheet response is only the login page that redirects to another XML file. When I copied back the final URL after the original file content is displayed, the URL is as below:
https://storage.googleapis.com/formfacade-public/1FAIpQLSfscYq_sbYcT2P3Sj3AvSD2zYKalIM0SKdPTESf1wE9Rq8qew%2F97dc1ee0-f212-11ea-95c3-bdb6c5ab13b3%2F2124651919%2FA%20Sample%20PDF.pdf?GoogleAccessId=firebase-adminsdk-pve0p%40formfacade.iam.gserviceaccount.com&Expires=1599671507&Signature=fBzWej0fEgF6Aw7oCHX%2FTTUfHbcep%2Bj%2B%2FhB3fYFUDeq0SFTuyJ6jTnLWQJmldD6XkVug0%2BNki7ZPNo2ESufvIfQjhVLKXgvp7UiQheJ4GYL%2BtXgFLaUyglgemmfp7KSvIvPxpMcpC2lR8em3E5YIvMRr9tcfzagvusQYHEb9mlD7k833bVoqFUVWuP%2FkP8tl%2BHYVL15kSXAjtFif4QZpu%2FFHwSik89Keo78LKTm0U8hZiAMeYDQZWF6w1pcKpy04md3xKtDPwZYCoUWOOtKkCI6JLskE5HweDvMCGnDbxW8o6SWD%2BIC%2FlaNC6%2BJ81OB10cuRqwQPEc9LnfgCZK7b1A%3D%3D
When I pasted the above link, I got to see as per screenshot below:-
. So, I'm guessing they don't share direct access link to the uploaded file so that we are left with the option to buy/subscribe the paid version.
Would anyone knows if there's any better altrnative(s) I could use to achieve this objective? Like maybe a link with API-key just like what I learnt from #Tanaike in his previous answer on Convert-API to convert pdf file to PNG? Of course it has some limits for the free version but it still is a very helpful solution.
You are not assigning content-type of the blob anywhere. But if you do the naming right it would not matter. In method 1 you are trying to set a name on the blob when you should be setting it on the file created from the Blob.
Try setting the name on the file after creating it.
Example:
function myFunction() {
var url ="http://www.africau.edu/images/default/sample.pdf";
var response = UrlFetchApp.fetch(url);
console.log(response.getResponseCode());
var blob=response.getAs('application/pdf');
var folder = "<SOME-FOLDER-ID>";
var fileName=decodeURIComponent(url.split("/").pop());
console.log("File named : "+fileName);
var file=DriveApp.getFolderById(folder).createFile(blob);
// Set the name to the created file after creating it!
file.setName(fileName);
}
For reference see class File.

Google scripts function to fetch curl data to Google Sheets

I'm trying to fetch some data to a google sheet. The code goes like this:
function ls() {
var url = "https://api.loanscan.io/v1/interest-rates?tokenFilter=BTC";
var params = {
"contentType": "application/json",
"headers":{"x-api-key": "KEY",
},
};
var json = UrlFetchApp.fetch(url, params);
var jsondata=json.getContentText();
var page = JSON.parse(jsondata);
Logger.log page
return page;
}
The Logger.log gives the correct Data, as you can see in the next link.
Log
However when I run the function in the google sheet, it returns a blank cell.
Please help, thank you.
You should write the Logger.log(page); with parentheses, because sheets is probably hanging on your Logger statement.
I don't have an API key for that site, but I do get the forbidden error response from the API when using =ls() in a cell in sheets.

Google Spreadsheet Script: UrlFetchApp upload string as file

I saw this SO thread to upload a file using UrlFetchApp.
Also I saw this SO thread to post a string as file in python requests (without having a file or creating a temp file).
I want to send a string as file in Google Spreadsheet Script, and based on the two threads above I think it should be possible to do it without creating a temp file in google drive.
My question is how in Google Spreadsheet Script I can pretend the string is coming from a file and pass it to UrlFetchApp?
Here is the base code I am working on:
var string = 'test';
var url = "https://api.telegram.org/.../sendDocument";
var chat_id = "12345";
var data = {'chat_id': chat_id,
'text':text} ;
var headers = { "Accept":"application/json",
"Content-Type":"application/json"
};
var options = { "method":"POST",
"headers": headers,
"payload" : payload
};
var response = UrlFetchApp.fetch(url, options);
Here is how I got it right to post a string as file:
var url = "https://api.telegram.org/.../sendDocument";
var blob = Utilities.newBlob('Test!', 'text/plain', 'report.txt');
var data = {
'chat_id' : '12345',
'document': blob
};
var options = {
'method' : 'POST',
'payload' : data,
};
UrlFetchApp.fetch(url, options);
Thanks to comment from #Jack Brown and google developer example for posting blobs (example titled: Make a POST request with form data.).

UrlFetch from Google Sheet exportLink['application/pdf'] not returning PDF data

I create and send a periodic email as an update from a Google Sheet. For various client reasons this is done 3 ways, as a link to the Sheet, and as attachments (PDF and XLSX).
This was working 'til recently. The XSLX attachment still works, but the PDF is no longer sent as a response to a UrlFetch to the file.exportLinks('application/pdf') url. No matter what the request headers it always returns as Content-Type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Did something else undocumented change that I am missing here?
function exportAsPDF(spreadsheetId) {
spreadsheetId = spreadsheetId || 'SECRET_ID';
var file = Drive.Files.get(spreadsheetId),
url = file.exportLinks['application/pdf'];
url += '&format=pdf&size=7&fzr=true&portrait=true&fitw=true&gid=0&gridlines=false&printtitle=false&sheetnames=false&pagenum=UNDEFINED&attachment=true'
var token = ScriptApp.getOAuthToken(),
response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var headers = response.getAllHeaders(); // revealing content-type returned isn't pdf
var pdfBlob = response.getBlob().getAs('application/pdf');
var pdfString = pdfBlob.getDataAsString(); // this naturally throws an error
return response.getBlob(); // this returns to the send mail script
}
I'm able to get PDFs using the utility from Convert all sheets to PDF with Google Apps Script.
That working script modifies the spreadsheet's edit URL into an export URL, which looks like:
https://docs.google.com/spreadsheets/d/<%SS-ID%>/export?exportFormat=pdf...
The advanced Drive service gives an export URL formatted like:
https://docs.google.com/spreadsheets/export?id=<%SS-ID%>&exportFormat=pdf...
I'd expect the URL provided by exportLinks to be more reliable than the hack in the working script. Apparently, it's not.
This has been raised as Issue 5114. Star it to receive updates.

Error uploading .xls file and converting to Google Spreadsheet via GAS

Prior Research
Please do not close this question as a duplicate because my question deals with how to resolve the specific error message I am receiving and not the general question of whether my objective is achievable or not — as some other related questions, yielded by my research and below detailed, have asked.
Related questions and why they do not apply here
This question, asked 7/27/2012, does not apply because it: (1) is too old (after 10 months, new solutions/methods might exist) and (2) does not deal with the specific error message I am experiencing.
This question, asked 10/12/2012, fails to apply for similar reasons.
My below code was copied from here which was forked from here. These are presumably, working solutions because they have been referenced as such from other question/answer exchanges here on Stack Overflow.
Objective
Programmatically, I am trying to:
Search my email inbox.
Find Excel (.xls) file attachments.
Upload those .xls file attachments to Google Drive.
While uploading, convert the .xls files into a Google Spreadsheet file format.
Problem
When I execute processInbox() (code shown at the bottom of this question), it fails and I get the error message shown below.
Error Message
Request failed for returned code 403.
Server response:
{
"error":{
"errors":[
{
"domain":"usageLimits",
"reason":"accessNotConfigured",
"message":"AccessNotConfigured"
}
],
"code":403,
"message":"AccessNotConfigured"
}
}
(line 13, file "DriveUpload")
Question
What am I doing wrong? And how can I fix it?
For example, do I need to do something special in my API console relative to setting up my project to, say, access Google Drive or something? What am I missing?
Note: I have not yet successfully implemented oAuth in any of my applications, yet.
Error Source
Line 13
(This is the code line referenced by the error message.)
var uploadRequest = UrlFetchApp.fetch("https://www.googleapis.com/upload/drive/v2/files/?uploadType=media&convert=true&key="+key, params); // convert=true convert xls to google spreadsheet
Code
The complete body of code I am working with is shown below for your reference. I extracted the error-triggering, “line 13,” and highlighted it above to help us focus on the proximate cause of the problem.
DriveUpload.js
function uploadXls(file) {
authorize();
var key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // <-- developer key
var metadata = { title: file.getName() }
var params = {method:"post",
oAuthServiceName: "drive",
oAuthUseToken: "always",
contentType: "application/vnd.ms-excel",
contentLength: file.getBytes().length,
payload: file.getBytes()
};
// convert=true convert xls to google spreadsheet
var uploadRequest = UrlFetchApp.fetch("https://www.googleapis.com/upload/drive/v2/files/?uploadType=media&convert=true&key="+key, params);
var uploadResponse = Utilities.jsonParse(uploadRequest.getContentText());
var params = {method:"put",
oAuthServiceName: "drive",
oAuthUseToken: "always",
contentType: "application/json",
payload: Utilities.jsonStringify(metadata)
};
var metaRequest = UrlFetchApp.fetch("https://www.googleapis.com/drive/v2/files/"+uploadResponse.id+"?key="+key, params)
return DocsList.getFileById(uploadResponse.id);
}
function authorize() {
var oauthConfig = UrlFetchApp.addOAuthService("drive");
var scope = "https://www.googleapis.com/auth/drive";
oauthConfig.setConsumerKey("anonymous");
oauthConfig.setConsumerSecret("anonymous");
oauthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oauthConfig.setAuthorizationUrl("https://accounts.google.com/OAuthAuthorizeToken");
oauthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
}
function processInbox() {
// get all threads in inbox
var threads = GmailApp.getInboxThreads();
for (var i = 0; i < threads.length; i++) {
// get all messages in a given thread
var messages = threads[i].getMessages();
// iterate over each message
for (var j = 0; j < messages.length; j++) {
// log message subject
var subject = messages[j].getSubject()
//Logger.log(subject);
if ( subject == "with xls attach" ){
Logger.log(messages[j].getSubject());
var attach = messages[j].getAttachments()[0];
var name = attach.getName();
var type = attach.getContentType();
//var data = attach.getDataAsString();
Logger.log( name + " " + type + " " );
var file = uploadXls(attach);
SpreadsheetApp.open(file);
}
}
}
};
Drive API is already built in GAS: https://developers.google.com/apps-script/reference/drive/
Use DriveApp and your problems go away ;-)
This maybe a temp solution
Step 1: Use a Google Form to Collect Data to a Google spreadsheet
Step 2: Add the Zoho Sheet App to your Google Drive
In a Zoho Sheet
Goto
Data Menu
»Link External Data
Select either
CSV
RSS/Atom Feed
or HTML Page
You can schedule it to update at specific time intervals
What I like is the VBA and Macros in Zoho
You can also do Pivot Charts and Tables
You can copy and paste Excel VBA into Zoho !
I have an Unpivot VBA that I will run on my Tabular dataset
before I can do a PivotChart
It is hard to beat all the functionality of Excel and I often fall back on familiar tools !
If I hear of anything I will post it
Good luck