way to access user's Google Finance portfolio? - google-api

I noticed that Google removed the Finance API for Google App Engine. All I want is a list of stock tickers that they have in their Google Finance portfolio. Is there any way to still pull this data from the end user's portfolio, given that the API has been removed? I'm trying to manually retrieve it given that I know the login and password (e.g., it's my own).
Is there any way to retrieve it manually through curl, by logging in to the Google services? It seems like it should be possible to log in and go to my portfolio page, retrieving the source.
I have tried the following code:
#!/bin/bash
function ClientLogin() {
read -p 'Email> ' email
read -p 'Password> ' -s password
local service=$1
curl -s -d Email=$email -d Passwd=$password -d service=$service https://www.google.com/accounts/ClientLogin | tr ' ' \n | grep Auth= | sed -e 's/Auth=//'
}
function GetFinance() {
curl -L -s -H "Authorization: GoogleLogin auth=$(ClientLogin finance)" "http://www.google.com/finance/portfolio?action=view&pid=1" &> output.html
}
GetFinance
However, this code only retrieves a page that tells me to log in. The solution does not need to use curl, but it must be an automated retrieval using some scripting language.
Thanks to x4avier, I learned about casperjs and was able to write a quick script to load the Google services login page, enter the username and password, and then fetch the Google Finance portfolio. I'm sure this would work with any other google service and page. I save the html of the portfolio to portfolio.html. Hopefully this helps someone else also.
var fs = require('fs');
var failed = [];
var links = [
"https://www.google.com/finance/portfolio?action=view&pid=13"
];
var casper = require('casper').create({
verbose: true,
logLevel: 'debug',
pageSettings: {
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false, // use these settings
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537
}
});
// print out all the messages in the headless browser context
casper.on('remote.message', function(msg) {
this.echo('remote message caught: ' + msg);
});
// print out all the messages in the headless browser context
casper.on("page.error", function(msg, trace) {
this.echo("Page Error: " + msg, "ERROR");
});
var url = 'https://accounts.google.com/ServiceLogin?service=finance';
casper.start(url, function() {
// search for 'casperjs' from google form
console.log("page loaded");
this.test.assertExists('form#gaia_loginform', 'form is found');
this.fill('form#gaia_loginform', {
Email: 'youraccount#gmail.com',
Passwd: 'yourpass'
}, true);
});
casper.each(links, function(casper, link) {
this.then(function() {
this.test.comment("Loading " + link);
start = new Date();
this.open(link);
});
this.then(function() {
var message = this.requestUrl + " loaded";
if (failed.indexOf(this.requestUrl) === -1) {
this.test.pass(message);
fs.write('portfolio.html',this.getPageContent(),'w');
}
});
});
casper.run();

You should consider using an headless browser like casper.js.
With it you can login to google, go to google finance and get the html of a page or of a particular css selector.
To login you will to use the fill() function, it works like this :
casper.start('http://admin.domain.tld/login/', function() {
this.fill('form[id="login-form"]', {
'username': 'chuck',
'password': 'n0rr1s'
}, true);
});
casper.run();
Then you can parse the page and the specific content with getHTML(), work as below :
casper.then(function() {
this.echo(this.getHTML('h1#foobar')); // => 'The text included in the <h1 id=foobar>'
});
CasperJs works with cookies and explore more than one page, it should fit your needs.
Hope it helps :)

What information do you want to retrieve exactly?
It's pretty easy to do that using python urllib and beautifulsoup
http://docs.python.org/2/library/urllib2.html
http://www.crummy.com/software/BeautifulSoup/bs4/doc/
I've done it myself to post and retrieve messages on different forums website. The only thing that is not cool is that you have to hardcode the id of some elements you want to retrieve.
Here's a sample of what I did for the login part
#!/usr/bin/python
import urllib
import urllib2
import cookielib
import BeautifulSoup
url = "https://accounts.google.com/ServiceLogin?hl=en";
values = {'Email': 'me#mymail.fr', 'Passwd' : '', 'signIn' : 'Sign in', 'PersistentCookie' : 'yes'} # The form data 'name' : 'value'
cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
data = urllib.urlencode(values)
response = self.opener.open(url, data)
print response
I filled some of the required info for the google login. But when I checked the POST request there was some others values you might need to add too in the values dict.
Here's the POST request I captured:
dsh:5606788993588
hl:en
checkedDomains:youtube
checkConnection:youtube:47:1,youtube:46:1
pstMsg:1
GALX:YU6dyLz2tHE
pstMsg:0
dnConn:
checkConnection:
checkedDomains:youtube
timeStmp:
secTok:
_utf8:☃
bgresponse:!A0LP9ks4H06eS0R0GKgonCCotgIAAAAiUgAAAAkqAOjHBiH2qA-EIczqcDooax5q8bxis...
Email:****#gmail.com
Passwd:mypassword
signIn:Sign in
PersistentCookie:yes
rmShown:1
I guess you will have to parse the login page using Beautifulsoup to get this values before you can actually send the form. I wonder if the casper example given above does that automatically, if it does you'd rather use it and then parse the portfolio page using Beatifulsoup of whatever you want.

Related

Get OAuth 2.0 token for google service accounts

Short explanation
I want to get a Auth2.0 token for access to some APIs in my Google Cloud Platform proyect.
Context
At the current time i have a Wordpress page that has to make the connection. Temporarily i will make a javascript connection with the client via Ajax (when all work successfully i will make this in another way, for example with a PHP server in the middle).
The process that has to execute in our GCP don't need the user to log in with his google account, for that reason we will make a google service account for server to server connections. All the threads executed by the API will be log like be executed by this service account that isn't owned by any real person.
When i generate the Ajax connection for get the token, this will be send to the following URL:
https://oauth2.googleapis.com/token
I send it on JWT coding.
The coded message is generated in this Javascript code:
`
var unixHour = Math.round((new Date()).getTime() / 1000);
var header = {
"alg":"RS256",
"typ":"JWT"
}
var data = {
"iss":"nombreoculto#swift-firmament-348509.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/devstorage.read_only",
"aud":"https://oauth2.googleapis.com/token",
"exp":(unixHour+3600),
"iat":unixHour
}
var secret = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCkhZH7TuaNO4XBVVVcE2P/hvHSsGXNu1D/FcCaMrW56BF/nbOlxAtbp07TCIOyrR1FEcJb+to66olSFnUVUWhWUB9zLbzKpULQoFmYECSWppUbCZd+bp271AFYZpxXFduziWuaG9BNxV2cmWTjLLlZI7FoIYFwLgPZHPWndY0E99lGEjmnH";
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
//document.getElementById("header").innerText = encodedHeader;
console.log(encodedHeader);
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
//document.getElementById("payload").innerText = encodedData;
console.log(encodedData);
var signature = encodedHeader + "." + encodedData;
signature = CryptoJS.HmacSHA256(signature, secret);
signature = base64url(signature);
console.log(signature);
//document.getElementById("signature").innerText = signature;
var jwt = encodedHeader + "." + encodedData + "." + signature;
console.log(jwt);
$.ajax({
url: 'https://oauth2.googleapis.com/token',
type: 'POST',
data: { "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion" : jwt} ,
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
success: function (response) {
alert(response.status);
},
error: function () {
alert("error");
}
});
`
Console:
Console output
The problem
The Ajax message generated in the script return "Invalid JWT signature".
send message API
ajax response API
Following the google documentation, this problem is for a bad coding of the message or a incorrect secret key.
You can see the code for generate the coding message in the previous script.
About the secret key, maybe i am not selecting the correct key for this task, here you have the steps i follow:
cred GCP
Inside the service account, i create a key in the "keys" section:
Keys GCP
As result this download this file:
File keys
I tried to use like secret key the "private_key" content of this file and additionally i tried to delete the line breaks (\n) of this and try again.
¿Is that correct?¿Or i dont use the corret key?
¿Maybe i make an incorrect coding?
*There aren't problems with share the key and account id because the key was disabled at the moment of share this thread and the project is only for testing purposes.

Does Google Script have an equivalent to python's Session object?

I have this python script and I want to get Google Script equivalent but I do not know how to "pass" whatever needs to be passed between next get or post request once I log in.
import requests
import json
# login
session = requests.session()
data = {
'LoginName': 'name',
'Password': 'password'
}
session.post('https://www.web.com/en-CA/Login/Login', data=data)
session.get('https://www.web.com//en-CA/Redirect/?page=Dashboard')
# get customer table
data = {
'page': '1',
'pageSize': '100'
}
response = session.post('https://www.web.com/en-CA/Reporting', data=data)
print(response.json())
I wonder if there is an equivalent to .session() object from python's requests module. I did search google but could not find any working example. I am not a coder so I dot exactly know that that .session() object does. Would it be enough to pass headers from response when making new request?
UPDATE
I read in some other question that Google might be using for every single UrlFetchApp.fetch different IP so login and cookies might not work, I guess.
I believe your goal as follows.
You want to achieve your python script with Google Apps Script.
Issue and workaround:
If my understanding is correct, when session() of python is used, the multiple requests can be achieved by keeping the cookie. In order to achieve this situation using Google Apps Script, for example, I thought that the cookie is retrieved at 1st request and the retrieved cookie is included in the request header for 2nd request. Because, in the current stage, UrlFetchApp has no method for directly keeping cookie and using it to the next request.
From above situation, when your script is converted to Google Apps Script, it becomes as follows.
Sample script:
function myFunction() {
const url1 = "https://www.web.com/en-CA/Login/Login";
const url2 = "https://www.web.com//en-CA/Redirect/?page=Dashboard";
const url3 = "https://www.web.com/en-CA/Reporting";
// 1st request
const params1 = {
method: "post",
payload: {LoginName: "name", Password: "password"},
followRedirects: false
}
const res1 = UrlFetchApp.fetch(url1, params1);
const headers1 = res1.getAllHeaders();
if (!headers1["Set-Cookie"]) throw new Error("No cookie");
// 2nd request
const params2 = {
headers: {Cookie: JSON.stringify(headers1["Set-Cookie"])},
followRedirects: false
};
const res2 = UrlFetchApp.fetch(url2, params2);
const headers2 = res2.getAllHeaders();
// 3rd request
const params3 = {
method: "post",
payload: {page: "1", pageSize: "100"},
headers: {Cookie: JSON.stringify(headers2["Set-Cookie"] ? headers2["Set-Cookie"] : headers1["Set-Cookie"])},
followRedirects: false
}
const res3 = UrlFetchApp.fetch(url3, params3);
console.log(res3.getContentText())
}
By this sample script, the cookie can be retrieved from 1st request and the retrieved cookie can be used for next request.
Unfortunately, I have no information of your actual server and I cannot test for your actual URLs. So I'm not sure whether this sample script directly works for your server.
And, I'm not sure whether followRedirects: false in each request is required to be included. So when an error occurs, please remove it and test it again.
About the method for including the cookie to the request header, JSON.stringify might not be required to be used. But, I'm not sure about this for your server.
Reference:
Class UrlFetchApp
You might want to try this:
var nl = getNewLine()
function getNewLine() {
var agent = navigator.userAgent
if (agent.indexOf("Win") >= 0)
return "\r\n"
else
if (agent.indexOf("Mac") >= 0)
return "\r"
return "\r"
}
pagecode = 'import requests
import json
# login
session = requests.session()
data = {
\'LoginName\': \'name\',
\'Password\': \'password\'
}
session.post(\'https://www.web.com/en-CA/Login/Login\', data=data)
session.get(\'https://www.web.com//en-CA/Redirect/?page=Dashboard\')
# get customer table
data = {
\'page\': \'1\',
\'pageSize\': \'100\'
}
response = session.post(\'https://www.web.com/en-CA/Reporting\', data=data)
print(response.json())'
document.write(pagecode);
I used this program

Express.js res.render not redirecting, just displayed in console

This time I want to use res.render to display html as success of DB update. I did it several times, but this time it doesn't work. It's not render html file, just displayed on chrome's console.
I think it caused because of async problem or duplicated response. I tried to many ways but I couldn't solve it, so pointers appreciated.
The code is related when the user paid service, increase user's level.
Get Access Token => Validate => res.render
app.post('/payment/validate', function(req, res, next){
// Get access token
request.post({
url : 'https://payment-company/get/token'
}, function(err, response, body) {
if(!err & response.statusCode == 200) {
var result = JSON.parse(body);
var accessToken = result.response.access_token;
// Validate payment (compare paid and would be paid)
request.get({
headers : { 'Authorization' : accessToken }
url : 'https://payment-company/find/paymentid'
}, function (err, response, body) {
if (!err && response.statusCode == 200){
var result = JSON.parse(body);
if (result.response.amount == req.body.price){
Members.findOne({id : req.user.id}, function(err, member){
// If no problem, update user level
member.level = 2;
member.save(function(err, result){
if (err) return next();
res.render('payment.view.result.ejs',
{
title : 'Success !',
description : 'level up.'
});
});
});
}
} else {
...
}
});
}
})
});
sorry to verbose code I tried to shorten code, No problem until res.render, res.render will work but it's not display page instead it just send html code to chrome's console.
Looks like there's a bit of a misunderstanding of how these requests work. What I think you intend:
Browser makes a GET request, server responds with an HTML document, the browser renders it
User takes an action
Browser makes a POST request, server responds with an HTML document, the browser renders it
What you've started coded on the frontend is an alternate method:
You make a POST request via AJAX, server responds with some JSON, you modify the current document with JavaScript to let the user know

Saiku Widget shows No Data

I am using Pentaho CDE and I am trying to put a Saiku analysis file inside the dashboard using Saiku Widget.
However I am getting No Data message on the screen and in the browser console I am getting an error 401 - Bad Credentials.
When I access the Saiku URL directly from the browser, I am getting JSON response. It is not working with-in pentaho CDE dashboard.
Can someone help me out with this?
You must edit the file /biserver-ce/pentaho-solutions/system/saiku/ui/js/saiku/embed/SaikuEmbed.js and then restart bi-server, because the content of this file is minified in CDF.js
In this SaikuEmbed.js the user and password are set in
var _settings = {
server: '/saiku',
path: '/rest/saiku/embed',
user: 'admin',
password: 'admin',
blockUI: false
};
but i don't have user admin with password admin, so when it's try to do a verification before ajax call it stack with 401 authorization required.
I modified
beforeSend: function(request) {
if (self.settings.user && self.settings.password) {
var auth = 'Basic ' + Base64.encode(
self.settings.user + ':' + self.settings.password
);
request.setRequestHeader('Authorization', auth);
return true;
}
},
with
beforeSend: function(request) {
if (Dasboards.context.user) {
return true;
}
},
You can comment all beforeSend, if you want.

JSONP pass api key

I've got an arduino uploading sensor data to cosm.com. I made a simple webpage on my local web server to query the cosm.com API and print out the values.
The problem is that if I am not logged into cosm.com in another tab, I get this popup.
The solution is to pass my public key to cosm.com, but I am in way over my head here.
The documentation gives an example of how to do it in curl, but not javascript
curl --request GET --header "X-ApiKey: -Ux_JTwgP-8pje981acMa5811-mSAKxpR3VRUHRFQ3RBUT0g" https://api.cosm.com/v2/feeds/120687/datastreams/sensor_reading
How do I pass my key into the url?:
function getJson() {
$.ajax({
type:'GET',
url:"https://api.cosm.com/v2/feeds/120687/datastreams/sensor_reading",
//This line isn't working
data:"X-ApiKey: -Ux_JTwgP-8pje981acMa5811-mSAKxpR3VRUHRFQ3RBUT0g",
success:function(feed) {
var currentSensorValue = feed.current_value;
$('#rawData').html( currentSensorValue );
},
dataType:'jsonp'
});
}
UPDATE:
It must be possible because hurl.it is able to query the api
http://www.hurl.it/hurls/75502ac851ebc7e195aa26c62718f58fecc4a341/47ad3b36639001c3a663e716ccdf3840352645f1
UPDATE 2:
While I never did get this working, I did find a work around. Cosm has their own javascript library that does what I am looking for.
http://cosm.github.com/cosm-js/
http://jsfiddle.net/spuder/nvxQ2/5/
You need to send it as a header, not as a query string, so try this:
function getJson() {
$.ajax({
type:'GET',
url:"https://api.cosm.com/v2/feeds/120687/datastreams/sensor_reading",
headers:{"X-ApiKey": "-Ux_JTwgP-8pje981acMa5811-mSAKxpR3VRUHRFQ3RBUT0g"},
success:function(feed) {
var currentSensorValue = feed.current_value;
$('#rawData').html( currentSensorValue );
},
dataType:'jsonp'
});
}
It should be much easier to get it to work using CosmJS. It is an officially supported library and provides full coverage of Cosm API.

Resources