Google Sheet Coinmarketcap requesting 1 single importxml instead of 1 request for each coin - arrays

I am developing a sheet in google sheet that pulls data from coinmarketcap with a script i've been trying to write.
I am a f. noob # coding.
I use the function importxml (i need to refresh the latest price for each coin, like 100 coins) in this script:
function CryptoRefresher() {
var spreadsheet = SpreadsheetApp.getActive();
var queryString = Math.random();
var link1 = "C";
var xpath = "D";
var destination = "E";
var Direction=SpreadsheetApp.Direction;
var NumeroRighe =spreadsheet.getRange("B"+(spreadsheet.getLastRow()+1)).getNextDataCell(Direction.UP).getRow();
for (var i = 2; i <= NumeroRighe; i++) {
var cellFunction1 = '=IMPORTXML("' + SpreadsheetApp.getActiveSheet().getRange(link1+i).getValue() + '?' + queryString + '", "'+ SpreadsheetApp.getActiveSheet().getRange(xpath+i).getValue() + '")';
SpreadsheetApp.getActiveSheet().getRange(destination+i).setValue(cellFunction1);
}
};
Example Data:
Cell B2 = "bitcoin"
cell C2 = "https://coinmarketcap.com/currencies/Bitcoin"
Cell D2 = "//div[#class='priceValue___11gHJ']"
Cell E2 = is the destination and will receive the bitcoin price
The problem is that it's really slow because it calls 1 coin per time.
Question: Is there a way to send ALL THE COINS REQUESTS in 1 single importxml call?
Like I'd like to collect all the coin names in column C (1 cell of column C has 1 different and unique Coin Name) to collect all the coin names that i am watching and ask for 1 single call to speed up the process?
(Is there a way to create an array, a list of the coin names and do 1 single call to coinmarketcap?)
I really can't figure that out and i hope what i'm asking is clear!
Thank you!
Alessandro

Given the structure of the webpage, it is currently not possible to have a single IMPORTXML call to pull multiple arbitrary currencies from the CoinMarketCap site.
However, they have a convenient API that can do that exactly, please see references below:
CoinMarketCap API / Cryptocurrency
And this should get you started in pulling information from the API:
Pulling Currency Data to Google Sheets

I'd suggest using a dedicated service to retrieve the data, for instance this request will give you the data you need without any parsing or signing up to 3rd party services
=IMPORTDATA("https://cryptoprices.cc/BTC")
Trying to parse a complex web page under active development is just prone to fail at some point.
As alternative, go straight to the source, by signing up to the CoinMarketCap api to get more up to date data. (Already mentioned above) You can sign up for the free tier API (333 req/day) at https://pro.coinmarketcap.com/signup/

Wow! Сryptoprices.cc it’s a great service.
But some cryptocurrencies don’t read clearly.
If you change the formula, add / the price is updated and it is correct.

Related

Google Sheets Apps Script: How do I loop through replaceText and pull values from one cell to replace in Google Docs template?

I followed a few tutorials to set up a Google Docs template for a job offer letter. I made mail merge fields in the Google Doc set up as "{{FirstName}}", "{{StartDate}}", etc. I have a Google Sheet and a Google Form. I made a sheet called "Fields" where in column D, I have the "merge fields" and then in Column E, I have the values. I have been pasting lines of code to replace the merge fields with values, one-by-one. I saw a solution in another forum about how to do a loop. But after hours of practice, I couldn't get it working.
Ideally, I would like maintain the merge fields in a Google Sheet, so that I can add more. It would be lovely if I could figure out how to write an Apps Script to read any merge fields on my Google Sheet and then do the replaceText function automatically.
Right now, I have the code working one-by-one, but every time I add merge fields, I have to edit the code to find it in my Google Sheet.
I saw some code here:
https://stackoverflow.com/questions/69545550/how-do-you-loop-through-an-object-and-replace-text#:~:text=Loop%20through%20values%20object%20by%20replacing%20the%20body.replaceText%20entries%20in%20your%20code%20with%20this%3A
that I was trying to replicate for a loop but I couldn't get it working :(
enter image description here
Google Sheet
Google Docs Template
const sheet = SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName('Form')
//Copy template documents in our destinationFolder
const copy = googleDocTemplate.makeCopy(sheet.getRange('Fields!E3').getValues()+' '+sheet.getRange('Fields!E4').getValues()+` - Offer Letter` , destinationFolder)
//Once we have the copy, we then open it using the DocumentApp
const doc = DocumentApp.openById(copy.getId())
//Create constants for the Google Doc Body and Header so we can use replaceText
const body = doc.getBody();
const docHeader = doc.getHeader().getParent();
//Replace text in Headers of Google Doc
docHeader.replaceText(sheet.getRange('Fields!D3').getValues(), sheet.getRange('Fields!E3').getValues()); //First Name
docHeader.replaceText(sheet.getRange('Fields!D4').getValues(), sheet.getRange('Fields!E4').getValues()); //Last Name
//Replace body text
body.replaceText(sheet.getRange('Fields!D2').getValues(), sheet.getRange('Fields!E2').getValues());
body.replaceText(sheet.getRange('Fields!D3').getValues(), sheet.getRange('Fields!E3').getValues());
body.replaceText(sheet.getRange('Fields!D4').getValues(), sheet.getRange('Fields!E4').getValues());
body.replaceText(sheet.getRange('Fields!D5').getValues(), sheet.getRange('Fields!E5').getValues());
body.replaceText(sheet.getRange('Fields!D6').getValues(), sheet.getRange('Fields!E6').getValues());
body.replaceText(sheet.getRange('Fields!D7').getValues(), sheet.getRange('Fields!E7').getValues());
body.replaceText(sheet.getRange('Fields!D8').getValues(), sheet.getRange('Fields!E8').getValues());
I created a sheet and template as shown.
Now using the following script replace all the placeholders with the text. Notice I deliberatly leave one out.
function replaceText() {
try {
let spread = SpreadsheetApp.getActiveSpreadsheet();
let sheet = spread.getSheetByName("Sheet1");
let values = sheet.getDataRange().getDisplayValues();
values.shift(); // remove header
let file = DriveApp.getFileById("1up..........").makeCopy(values[1][4]+" "+values[2][4]+" - Letter");
let doc = DocumentApp.openById(file.getId());
let body = doc.getBody();
values.forEach( row => {
body.replaceText(row[3],row[4])
}
);
}
catch(err) {
console.log(err);
}
}
With the following results
Reference:
Array.forEach()
Body.replaceText()

How to create a loop to extract my Twitter followers' followers through Tweepy V2

Some of the answers on SO currently does not work with API V2. Currently, I made this Frankenstein code to extract the followers from a list of 110 users (let's call this list A users). I then want to organise my data into a dataframe so that I can see a column of list A users and next to it is the list of followers for each user. Something like this:
List_A_User_1 | List_A_Follower_1
List_A_Follower_2
List_A_Follower_3
It should take around 110 minutes (since every 15 minutes I can make 15 API calls). I am currently on Tweepy and using a Twitter developer account. However, it has been 20 hours and the code ran before the Kernel died. How may I be able to execute what I want to do?
This is the code so far:
twitter_handles = List A
twitter_handles = df['id']
new_follower_ids = []
ids = []
for user in twitter_handles:
current_user_followers = []
while True:
try:
for page in tweepy.Paginator(client.get_users_followers, id=next_users, max_results=1000, user_fields='created_at'):
current_user_followers.extend(page)
except tweepy.TooManyRequests:
print('Hit Twitter API rate limit.')
for i in range(3, 0, -1):
print("Wait for {} mins.".format(i * 5))
time.sleep(5 * 60)
new_follower_ids.extend(current_user_followers)
ids.extend([user for _ in current_user_followers])
new_followers_df = pd.DataFrame({
"IDs": ids,
"Follower_ID": new_follower_ids})

AngularJS - any way to export xls with dynamic content?

I'm investigating for a client feature and I didn't reach the right answer.
This is quite simple : the user edits a full table with datas ( numbers ), chooses which cells receive the sum of which cells and export it.
In Angular we can keep the calculation and hide it to show the result. But what I would like to do is to keep the calculation active when exporting on xls.
For ex.
Cell1 = 25 Cell2 = 45
Cell3 = 70 (Sum(Cell1,Cell2));
In the XLS file It should keep the Sum() function instead of a "flat" 70.
Am I clear enough ? Does someone know a library that can do this ? or the best process to succeed in this feature ?
Excel files are essentially XML Documents.
However building Excel using plain XML is a crazy job...
You can try using the library (ClosedXML) if you are using .NET. https://closedxml.codeplex.com/
It makes much easir to build Excel files.
var wb = new XLWorkbook();
var ws = wb.AddWorksheet("Sheet1");
ws.Cell("A1").SetValue(1).CellBelow().SetValue(1);
ws.Cell("B1").SetValue(1).CellBelow().SetValue(1);
ws.Cell("C1").FormulaA1 = "\"The total value is: \" & SUM(A1:B2)";
var r = ws.Cell("C1").Value;
Assert.AreEqual("The total value is: 4", r.ToString());
// It also works if you use: ws.Cell("C1").GetString()

Google Forms as Multiple Choice Quiz - How to Provide Results

I've built a google form for a multiple choice quiz, with a linked spreadsheet for results, which works very well. I have a specific problem, which is that I'd like to present the user's results to them (i.e. how many answers they got right/wrong). The approach I've taken so far is:
create an extra sheet on the spreadsheet with a formula to calculate the number of correct answers for each response. This gives me two columns "Full Name" and "Scores"
embed the form into a google site
create a google apps script to read the results sheet and display output
embed the above into the same site below the form as an Apps Script Gadget
Currently I am able to display all of the results recorded so far. See here:
https://sites.google.com/site/mcqtest123/home
The script looks like:
// Script-as-app template.
function doGet() {
var app = UiApp.createApplication();
var title = app.createLabel("Survey Results").setStyleAttribute("fontSize","16px");
app.add(title);
//readRows(app);
calculateScores(app);
return app;
};
function calculateScores(app) {
var sheet = SpreadsheetApp.openById("0AlNR-ou0QtandFFzX1JCU1VRdTl0NVBRNTFjOUFhd1E");
var responseSheet = sheet.getSheetByName("Form Responses");
var allData = responseSheet.getDataRange().getValues();
var correct = allData[1];
var responses = allData.slice(2);
//Logger.log("Timestamp, name, score");
Logger.log("Name, Score");
for (var i = 0; i < responses.length; i++) {
var timestamp = responses[i][0];
var name = responses[i][1];
var score = 0;
for (var j = 2; j < correct.length; j++) {
if(responses[i][j] == correct[j]) {
score += 1;
}
}
//var output = timestamp + ", " + name + ", " + score + "/" + correct.length
var output = name + ", " + score + "/" + correct.length
print(app, output);
}
};
function print(app, line) {
Logger.log(line);
app.add(app.createLabel(line));
};
So this leaves two problems:
When the page loads, it loads the scores for all the respondents. I'd like to be able to present only the score for the person who filled out the form.
The scores don't get updated when the form is completed - only when the page is refreshed.
For problem 1), I wondered if there was some way to access the data in the form iframe (e.g. using document.getElementById('targetFrame'), except that google scripts don't seem to have access to the document model) to only display results of the person whose full name matches the name in the form (of course you could then view someone else's results if you know what they'd put as their full name, but without using the timestamp I don't see away round this).
For problem 2), I wondered if there was some way to trigger the script when the responses sheet was updated. However when I go to the spreadsheet and Tools->Script Manager I get the message "No scripts found", so I don't know how to add this trigger.
If you make your own form using HtmlService or UiApp and then that POSTing to your script to populate the spreadsheet, then you can generate a UID in a hidden field and use this to determine the results someone needs to see.
This will be the results as instant feedback to their answers to the quiz. To see these at a later date, you could then also add a bookmarkable link that also included that UID as a parameter. So your doGet() would look for a e.parameters.uid for example.
From Google Forms as they stand I am not so sure. you could potentially, with the new form styles, offer a pre-filled field with such a UID, but the route from form submission to your webapp is again unclear.

Copy range in google docs to another sheet

I have Google form that gets filled in by a few users. Works great but has it's limitations.
I'd like to copy the data entered from the active sheet to a new sheet called "work", all information except the first row that is. In the first row I have a few array formulas that populate some cells as new data is entered on the active sheet.
The second sheet (work) has a header row with all the formatting, data validation, some formulas etc (row 1). This information can not be applied when a new record is added via the form.. so I am told..
Thus, once the data has been copied from the active sheet (called active) I'd like the new data to be formatted as per the heading row (row 1) of the "work" sheet with all the formatting, validation, formulas etc being applied to the new data.
Is this doable? I am a noob when it comes to scripting so a complete solution would be highly appreciated.
here is a sample form you can play with
https://docs.google.com/spreadsheet/ccc?key=0AplugTacg-08dFNRUHROSW82bDhESkxBdjVTV0NOLUE
First thing i noticed one can not just copy/paste as the array formulas will bong things up so it has to be a paste special - values only
Any help greatly appreciated.
I'm struggling a bit with the logic behind what you're doing, but I've attempted a solution in sheet 'work2' in this copy of your spreadsheet. Perhaps have a play and report back what's not right or missing.
The script is this:
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('work2');
var nextRow = sheet.getRange(sheet.getLastRow() + 1, 1, 1, 9);
sheet.getRange(2, 1, 1, 9).copyTo(nextRow);
var sLength = e.values[2].length;
var huuh = e.values[3] * sLength;
var pending = e.values[3] * e.values[3] / huuh;
var nextMonth = e.values[3] + pending;
nextRow.setValues([[e.values[0], e.values[1], huuh, e.values[2], sLength, e.values[3], 'Please select action', pending, nextMonth]]);
}
and has an "on form submit" trigger attached to it.

Resources