Import data from yahoo finance to Google sheets [duplicate] - google-sheets

This question already has answers here:
Scraping data to Google Sheets from a website that uses JavaScript
(2 answers)
Closed last month.
I want to import the data from options tab in yahoo finance to my google sheet. It is this tables:
Picture with the table I want to import
First of all, you can see a box with different dates that when you change the date the URL change. The difference between the URLS is that you need to sum to the previous number 604800 and then you get the correct URL.
Well if you use Excel, you can download the data (is in the table 3 the ones I want) without any issue, but you need to be changing the website manually every time that the date change.
So I was thinking to use the ImportXML or ImportHTML of google sheet. For example if you use in the main page: https://finance.yahoo.com/quote/VZ?p=VZ
This formula: =importXML("https://finance.yahoo.com/quote/VZ?p=VZ";"//*[#id='quote-header-info']/div[3]/div[1]/div/span[1]")
You will get the value of the stock in that moment but if you change the website url for the one of the options: =importXML("https://finance.yahoo.com/quote/VZ/options?date=1618531200&p=VZ";"//*[#id='quote-header-info']/div[3]/div[1]/div/span[1]")
You got a NA value... even if the value is there and the HTML code of the website is the same... and this for me does no make sense.
So I do not know how I should do to can download the data from the tab "options", and is frustrating cause it must be possible as it is really "simple" to get it in Excel.
Some suggestion?

I am not sure about that function but I have downloaded historical stock pricing on Yahoo using a script.
function importCSVFromWeb() {
// Provide the full URL of the CSV file.
var csvUrl = "https://query1.finance.yahoo.com/v7/finance/download/MSFT?period1=1577806579&period2=1609428979&interval=1d&events=history&includeAdjustedClose=true";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}
Here is my sheet after running the script

Many thanks, it worked well. I slightly adapted code to work as a formula:
function importCSVFromWeb( url ) {
// Provide the full URL of the CSV file.
var csvUrl = url; // url example = "https://query1.finance.yahoo.com/v7/finance/download/%5EGSPC?period1=1495670400&period2=1653436800&interval=1wk&events=history&includeAdjustedClose=true"
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheet = SpreadsheetApp.getActiveSheet();
// sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
return csvData;
}

Related

Is there a way to use FILTER with multiple Sheets containing a specific phrase in Google Sheets?

I will try to be as clear as possible. Here is the example piece: link
What I want to happen is that the Filter formula will search for any Sheet containing “Form Responses” and then display the results. You can see on the Current sheet how I’ve been doing, but this is more tedious and leads to issues of the first formula begins to overwrite the next one, etc. On the Wanted tab, I’ve laid out how I imagine it and put a note in A7. Any help offered is greatly appreciated!
You can get started with this script:
function getSheetResponses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Wanted");
var getCellValue = sheet.getRange("A7").getValue(); //Gets the name of your designated sheet on "Wanted Sheet" cell "A7"
var getName = ss.getSheetByName(getCellValue);
var getNameValue = getName.getRange(2,5,getName.getLastRow(),1).getValues(); //Gets all the values of Column E on any defined sheet names based on getCellValue
var datalength = getNameValue.length;
Logger.log(datalength);
sheet.getRange(8,6,datalength,1).setValues(getNameValue); //Puts the data on Wanted Sheet Column F
}
What this does is it gets the sheet name on cell A7, and populates the data on Column F row 8 on the "Wanted" sheet like so:
Now, the data it populates on the "Wanted" sheet came from Form Responses 1 based on the sample piece you have provided:
If ever you would want to relocate which specific row or column the data would be pasted on "Wanted" Sheet. You can refer to this documentation on how to modify the rows and columns on sheet.getRange()
Reference:
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangerow,-column,-numrows,-numcolumns

googlesheets gives old or cached data when downloading with curl

I'm using this url to download a googlesheet programmatically https://docs.google.com/spreadsheets/d/{SHEET_ID}/export?gid=0&format=csv
For some reason every once in a while it gives old data, like 1 week old or something. This is completely random. Sometimes it even shows fresh data, and goes back to old data the next request.
The sheet in question is public but importing data from a private sheet like this
=QUERY(IMPORTRANGE("https://docs.google.com/spreadsheets/d/SHEET_ID", "sheet!A:Z"), "SELECT * WHERE Col1 LIKE '%keyword%'", 1)
The private sheet is also importing data from another sheet. Anything I can do to prevent this seemingly non-deterministic bug?
Similar behaviour observed with a published sheet which is designed to show time and a live schedule. "Recalculate every minute" setting didn't help. Solution is to put some value into a cell with a script. The script is set to run every minute.
function Somechanges() {
var someValue = Math.random();
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('J1').activate();
spreadsheet.getCurrentCell().setValue(someValue);
};

Google Sheets - Pushing a row to a second spreadsheet based on a value being entered

I'm new to this,
I have 2 google spreadsheets:
Spreadsheet A: The active sheet Containing multiple tabs with information to be Pushed to B.
Spreadsheet B: A spreadsheet with a single tab. The same headers and structure as spreadsheet A.
Based on the user selecting the answer "Yes" in the first column of any of the 1 tabs in Spreadsheet A, I would like that entire row to move over to Spreadsheet B.
I have modified a script that works on a single spreadsheet (ie moving rows from tab to tab) to attempt to get it to work between spreadsheets:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tss = SpreadsheetApp.openById('B').getSheetByName('Sheet 1');
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(r.getColumn() == 1 && r.getValue() == "Yes") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var target = tss.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
}
}
Probably needless to say, this yields no result. Having searched through a number of posts and forums I only see individuals posting about how to move rows between tabs but not between entirely separate spreadsheets. Is it even possible to do this? If so, what am I doing wrong in the script?
Thank you so much for anyone who takes the time to assist.
Anthony
Following a dialogue with the OP in the comments section, it was indicated that the original spreadsheet did not to be kept secret.
Consequently, the desired functionality can be provided by using a combination of IMPORTRANGE() and QUERY() in the spreadsheet with no need to use Google App Script. For instance,
=QUERY(IMPORTRANGE(url,range),"select A where B matches 'Yes'") or similar
This imports data from a second spreadsheet and then the QUERY() function acts as a way of filtering the imported range by certain criteria.
Once the imported range is authorised, the editors of the spreadsheet can access it by, e.g. removing or modifying the query. You could prevent this by protecting that particular cell, if needed.

Want an email sent to me every time conditional formatting is applied

I have a spreadsheet that is automatically updated with tweets from certain Twitter lists. I have conditional formatting applied to the sheet that if there is a swear word within one of the tweets, it will highlight that particular cell red.
What I want is to have the cell (or even the entire spreadsheet) emailed to me whenever conditional formatting is applied. Is this possible?
Also, is there a way to have the spreadsheet's contents go into an "archive" sheet each day so that the main sheet has fresh content each day?
Thanks for your help!
So far, I've been working on the "archiving" script. What I have so far is below:
function importData() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //source ss
var sheet = ss.getSheetByName("Twitter"); //opens the sheet with your source data
var values = sheet.getRange("A:G").getValues(); //gets needed values
var ts = SpreadsheetApp.openById("1g5XaIycy69a3T2YcWhcbBy0hYrxSfoEEz8c4-zP63O8"); //target ss - paste your key
ts.getSheetByName("Archives").getRange("A:G").setValues(values);}
It says range height in line 11 is wrong.
Here is my snippet of code I'm trying to use to get an email when a swear word is used. I feel like I'm on the cusp, but not quite there yet.
function onEdit(event)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
var range = sheet.getRange(cell.getRow(),1,1,sheet.getDataRange().getLastColumn());
var note = cell.getBackground()
var email = "antadrag#gmail.com";
var subject = "Notice of possible inappropriate tweet";
message = cell.getValue();
if(message.contains ("piss")) {
range.setBackgroundRGB(255, 0, 0);
MailApp.sendEmail(email, subject, message);
}
};
To answer your first question, I agree with Dougs suggestion in the comments. The trigger you use to detect a swearword would be the best place to call a function to email you, rather then waiting for a conditional formatting change.
With regards to your query on how to archive the data, your making life a little too difficult for yourself with fetching the ranges and copying them to sheets etc. The 'copyTo()' operation is your friend here, as that will copy the entire sheet to another spreadsheet while preserving conditional formatting.
Here's a sample of how this could possibly work:
function importData() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //source ss
var sheet = ss.getSheetByName("Twitter"); //opens the sheet with your source data
var ts = SpreadsheetApp.openById('SHEET ID');//Opens destination spreadsheet
sheet.copyTo(ts);//Copy the data to the destination sheet.
sheet.clear();//Clear the source sheet.
//Past this point it's optional, and only if you want to rename the destination sheet.
ts.getSheetByName("Copy of Twitter").activate();//Get the destination sheet by name.
var date = new Date().getDate();//Random variable for the sheets new name
ts.renameActiveSheet(date);//Set the new sheets name.
}
This will open your source sheet, copy the data to a new spreadsheet of your choice and clear the source sheet of data. Optionally, I've added a few lines that rename the destination sheet to a variable of your choice so that it's not easy to understand when it was copied (I suggest date or time, but it can be whatever you want really).

Hyperlink to a specific sheet

I would like to open a specific sheet of a Google Sheets from a hyperlink in another spreadsheet.
I have different links in my master spreadsheet and each should have a hyperlink to the same slave spreadsheet but to a different sheet.
I know hyperlink function but it doesn't go to a specific sheet.
You can use this custom script (Tools > Script Editor) function and connect it with e.g. custom drawing (Insert > Drawing... > Save and Close, then right click on new drawing> Assign Script... > "goToSheet2")
function goToSheet2() {
goToSheet("Sheet2");
}
function goToSheet(sheetName) {
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
SpreadsheetApp.setActiveSheet(sheet);
}
Update:
In the newest version you can select cell and add link (Insert > Link) and select link to specific sheet directly:
The HYPERLINK function can link to another sheet in the same workbook; if you observe the URL of the spreadsheet, at the end of it there is #gid=x where x is unique for each sheet.
The problem is, it will open the sheet as a new instance of the spreadsheet in another tab, which is probably not desirable. The workaround would be to insert images or drawings as buttons, and assigning a script to them that will activate specific sheets.
I personnaly did this based on what #rejthy said:
In scripts I created this function:
/**
* Return the id of the sheet. (by name)
*
* #return The ID of the sheet
* #customfunction
*/
function GET_SHEET_ID(sheetName) {
var sheetId = SpreadsheetApp.getActive().getSheetByName(sheetName).getSheetId();
return sheetId;
}
and then in my sheet where I need the link I did this: =HYPERLINK("#gid="&GET_SHEET_ID("Factures - "&$B$1);"Année en cours")
So what I understand from the OP is that you have one master spreadsheet that you want to have links to individual sheets, where one or more of those sheets may be in single or multiple spreadsheet files.
The HYPERLINK function only turns a URL into a hyperlink and is really only useful when you want to have hypertext instead of just a link. If you enter the raw URL as the data, it's automatically turned into a hyperlink, so there's no additional work.
As mentioned in other answers, the solution is to have the spreadsheet's URL then use the gid value to calculate the link to the desired sheet within the spreadsheet. You can write a simple app that collects all of the individual sheets' links and writes them into the master.
Below are some snippets of pseudocode (Python) that can help you get started. I'm leaving out all the boilerplate auth code, but if you need it, see this blog post and this video. The code below assumes your API service endpoint is SHEETS.
This reads a target spreadsheet to build links for each of its sheets:
# open target Sheet, get all sheets & Sheet URL
SHEET_ID = TARGET_SHEET_DRIVE_FILE_ID
res = SHEETS.spreadsheets().get(spreadsheetId=SHEET_ID,
fields='sheets,spreadsheetUrl').execute()
sheets = res.get('sheets', [])
url = res['spreadsheetUrl']
# for each sheet, dump out its name & full URL
for sheet in sheets:
data = sheet['properties']
print('** Sheet title: %r' % data['title'])
print(' - Link: %s#gid=%s' % (url, data['sheetId']))
Instead of printing to the screen, let's say you stored them in a (name, URL) 2-tuple array in your app, so bottom-line, it looks something like this list called sheet_data:
sheet_data = [
('Intro', 'https://docs.google.com/spreadsheets/d/SHEET_ID/edit#gid=5'),
('XData', 'https://docs.google.com/spreadsheets/d/SHEET_ID/edit#gid=3'),
('YData', 'https://docs.google.com/spreadsheets/d/SHEET_ID/edit#gid=7')
]
You can then write them to the master (starting from the upper-left corner, cell A1) like this:
SHEET_ID = MASTER_SHEET_DRIVE_FILE_ID
SHEETS.spreadsheets().values().update(
spreadsheetId=SHEET_ID, range='A1',
body={'values': sheet_data},
valueInputOption='USER_ENTERED'
).execute()
Some caveats when using gid:
The first default sheet created for you (Sheet1) always has a gid=0.
Any sheets you add after that will have a random gid.
Don't bank on a gid=0 for the 1st sheet in your spreadsheets however as you or someone else may have deleted the original default sheet, like my example above.
If you want to see more examples of using the Sheets API, here are more videos I've made (along with posts that delve into each code sample):
Migrating SQL data to a Sheet plus code deep dive post
Formatting text using the Sheets API plus code deep dive post
Generating slides from spreadsheet data plus code deep dive post
Then when you open up the master in the Sheets UI, you can clickthrough to any of the individual sheets, regardless of which spreadsheet files they're in. If you want them automatically opened by another app or script, most programming languages offer developers a ways to launch a web browser given the target URL. In Python, it would be the webbrowser module (docs):
import webbrowser
webbrowser.open_new(url) # or webbrowser.open_new_tab(url)
Alternatively, you can try creating a custom function. With the spreadsheet open, click the Tools menu, then Script editor.... Paste the code into the editor:
/**
* Gets the Sheet ID from Sheet Name
*
* #param {string} input The Sheet Name
* #return The Sheet ID
* #customfunction
*/
function SHEETID(input) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tab = ss.getSheetByName(input);
return tab.getSheetId();
}
Save, refresh the spreadsheet, and then type in your custom function
=SHEETID("Your Custom Sheet Name")
=SHEETID(A1)
And voila! The unique ID for the tab (in the current spreadsheet) is output. You can hyperlink to it by using the following formula:
=HYPERLINK("#gid="&SHEETID(A1),"Link")
In case you want to create a link to another sheet which will open the sheet in the same browser tab here is what you want to do:
1. Get the id of the sheet. Check the link in your browser and you will see #gid=x where x is the sheet id
2. Then you want to set the formula (hyperlink) to the cell and make it show as a hyperlink
SpreadsheetApp.getActiveSheet().getRange("A1").setFormula('=HYPERLINK("#gid=X","test")').setShowHyperlink(true);
If you don't use setShowHyperlink(true) it will be shown as a regular text.
This is basically a code version for the update provided by #rejthy above

Resources