Skip to content

Instantly share code, notes, and snippets.

@kshwetabh
Last active June 17, 2018 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kshwetabh/feff379200c61151c369 to your computer and use it in GitHub Desktop.
Save kshwetabh/feff379200c61151c369 to your computer and use it in GitHub Desktop.
Xoom Exchange Rate Trend - Draws a graph indicating the exchange rate trend of Xoom.com Online Money Transfer Website.
/**
* Services combined together:
* ~Yahoo Pipes~, Gmail, Google App Script, GDrive, Google Charts
*
* This is a Google App Script Web App that draws a Column Graph highlighting the current and historical exchange rate trend of
* Xoom Money Transfer. Created this simple app to keep an eye on the $ to Rupee up/down trend.
* Has a related excel sheet also.
*
* Output (snapshot): https://plus.google.com/photos/108969069990423509081/albums/6115274347350257297?authkey=CKOFv9-t77O4kAE
*
* How to (re)use this script:
* - Go to Google Drive (https:\\drive.google.com)
* - Create a new Spreadsheet
* - Go to Tools -> Script Editor menu
* - Copy and paste this entire script in the script file (eg. in Code.gs file)
*
* One time Configuration:
* - You need to replace the dummy SPREADSHEETID with your newly created SpreadSheetID
* Run getId() method in Google App Script and check logs to get the SpreadSheetID
* - You will need to grant permission to Google Drive (for spreadsheet update), external requests (to use ~yahoo pipes URL~ Google Apps Script) and Gmail (to pull old historical XOOM data from gmail).
*
* Optionally configure the trigger in the App script to run the updateDailyXchangeDataToSpreadsheet() method everyday (for eg at 4-5 PM everyday)
*
* You can specify the number of days of data you want to see in the chart by passing p=value as query param in the Web App link
* https://script.google.com/macros/s/AKfycbwUeHXu5p4WkHZg4oKsHx6BlN8OIHHIu2xxxx-xxxxx-xxxxx/dev?p=25
*
*/
/**
Has a related excel sheet also.
*/
var DEFAULTNOOFDAYS = 25, //if no parameter specified in WebApp URL
QUERIEDNOOFDAYS = 0,
SPREADSHEETID = 'YOUR_SPREADSHEET_ID_GOES_HERE';
/*
* Fetch daily xoom rates and update in a spreadsheet. Use web service to then respond back a Column Chart to highlight the trend.
*/
function updateDailyXchangeDataToSpreadsheet() {
var sheet = SpreadsheetApp.getActiveSheet(),
lastRow = sheet.getLastRow(); //need to append data at the end
var rate = getDailyXchangeRateFromXoom(),
date = new Date();
sheet.getRange(lastRow+1,1).setValue(Utilities.formatDate(date, "GMT", "MM/dd/yyyy"));
sheet.getRange(lastRow+1,2).setValue(rate);
}
/*
* Fetch today's exchange rate from Xoom's website
*/
function getDailyXchangeRateFromXoom() {
var html = UrlFetchApp.fetch('https://www.xoom.com/india/fees-fx').getContentText();
var doc = XmlService.parse(html);
var html = doc.getRootElement();
var menu = getElementsByClassName(html, 'cp-grn-highlight')[0]; //Exchange rate usually in the first child
var output = XmlService.getPrettyFormat().format(menu);
return menu.getText().replace('1 USD = ', '').replace(' INR', '').trim().substring(0,5);
}
/*
* Locates an HTML Dom element by ClassName
*/
function getElementsByClassName(element, classToFind) {
var data = [];
var descendants = element.getDescendants();
descendants.push(element);
for(i in descendants) {
var elt = descendants[i].asElement();
if(elt != null) {
var classes = elt.getAttribute('class');
if(classes != null) {
classes = classes.getValue();
if(classes == classToFind) data.push(elt);
else {
classes = classes.split(' ');
for(j in classes) {
if(classes[j] == classToFind) {
data.push(elt);
break;
}
}
}
}
}
}
return data;
}
/**
* To access the spreadsheet data from a web app you must create/save the sspreadsheet id.
* This method must be run manually once by the user for the webapp to get data from the spreadsheet properly
*/
function getId() {
var ui = SpreadsheetApp.getUi(),
id = SpreadsheetApp.getActiveSpreadsheet().getId();
Logger.log(id);
SpreadsheetApp.getUi().alert(id);
}
function getXchangeDataFromSpreadSheet(noOfDays) {
var sheet = SpreadsheetApp.openById(SPREADSHEETID),
data = sheet.getDataRange().getValues().reverse(),
arrExchngRates = [];
//code here looks weird. Little explanation is needed
//if noOfDays passed in query parameter is valid and less than no of records in spreadsheet, use it,
//otherwise use the DEFAULTNOOFDAYS
if (noOfDays === null || noOfDays === '' || noOfDays < 1 ) {
noOfDays = DEFAULTNOOFDAYS; //if noofdays invalid in query string, set it to default value
}
var len = noOfDays > data.length ? DEFAULTNOOFDAYS : noOfDays; //noOfDays > DEFAULTNOOFDAYS > data.length
QUERIEDNOOFDAYS = len; //to be displayed on chart title
for (var i = 0; i < len; i++) {
arrExchngRates.push([getDateMonth(data[i][0]), data[i][1]]);
}
return arrExchngRates;
}
/**
* Respond back with the chart when the WebApp URL is invoked
*/
function doGet(e) {
//if URL has today parameter, return today's rate instead of graph
if (e.parameters["today"]) {
return ContentService.createTextOutput(JSON.stringify({rate:getDailyXchangeRateFromXoom()})).setMimeType(ContentService.MimeType.JSON);
}
var noOfDays = e.parameters["p"];
Logger.log(noOfDays); //input param from query string p=20
var dataTable = Charts.newDataTable()
.addColumn(Charts.ColumnType.STRING, "Dates")
.addColumn(Charts.ColumnType.NUMBER, "Rates");
var arrExchngRates = getXchangeDataFromSpreadSheet(noOfDays).reverse();
//Logger.log(arrExchngRates);
for (var i = 0; i < arrExchngRates.length; i++) {
dataTable.addRow(arrExchngRates[i]);
}
dataTable.build();
var textStyleBuilder = Charts.newTextStyle().setFontSize(10),
style = textStyleBuilder.build();
// Build the chart.
var chart = Charts.newColumnChart()
.setDataTable(dataTable)
.setColors(["rgb(66, 133, 244)"])
.setDimensions(950, 400)
.setXAxisTitle("Date")
.setYAxisTitle("Rupees")
.setTitle("Xoom Exchange Rate Trend ("+QUERIEDNOOFDAYS+" Days)")
.setLegendTextStyle(style)
.setXAxisTextStyle(style)
.build();
// Add our chart to the UI and return it so that we can publish
// this UI as a service and access it via a URL.
var ui = UiApp.createApplication();
ui.add(chart);
return ui;
}
function getDateMonth(dateString) {
var dateArray = dateString.split("/");
var year = dateArray[2];
var day = dateArray[1];
var month = dateArray[0];
return day + "/" + month;
}
/**
* Run this method once to pull all historical Xoom Rates from your Gmail Inbox into the spreadsheet
*/
function updateOldXchangeDataToSpreadsheet() {
var sheet = SpreadsheetApp.getActiveSheet(),
lastRow = sheet.getLastRow();
// Which Gmail Label should be searched? you can specify Inbox, Sent, etc.
// Not mandatory, but specifying a subset (like search only within xoom filter) makes the response faster
var label = 'xoom'; //This is a label defined in Gmail to filter all mails with subject 'Today at Xoom'
// Retrieve all threads of the specified label
var threads = GmailApp.search("in:" + label);
threads = threads.reverse();
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
for (var m = 0; m < messages.length; m++) {
var msg = messages[m],
xchngRate = msg.getSubject().substring(9,14); //Subject is in format: "Rupee at 61.30 Today at Xoom"
sheet.getRange(lastRow+1+i,1).setValue(msg.getDate());
sheet.getRange(lastRow+1+i,2).setValue(xchngRate);
}
}
}
Copy link

ghost commented Jul 23, 2015

Good effort Kumar. Unfortunately Yahoo will be discontinuing pipes on Aug 30th 2015. This will affect your script.
Ref: http://pipes.yqlblog.net/

@kshwetabh
Copy link
Author

Updated the code to remove dependency on Yahoo Pipes. Now the Xoom.com scraping in done from within Google Apps Script itself.

@javacodeator
Copy link

Under function getDailyXchangeRateFromXoom()
while html parsing at below line of code
var doc = XmlService.parse(html);

I am getting error "The entity name must immediately follow the '&' in the entity reference."

Looks like below fetch call is getting incomplete html
var html = UrlFetchApp.fetch('https://www.xoom.com/india/fees-fx').getContentText();

Below is the html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment