Skip to content

Instantly share code, notes, and snippets.

@haveaguess haveaguess/HSBC.js forked from benjie/HSBC.js
Created Oct 8, 2016

Embed
What would you like to do?
HSBC Personal Statement to CSV
/******************************
HSBC Personal Statement to CSV
v0.5
Copyright: Benjie Gillam (2012)
License: WTFPL v2.0 ( http://en.wikipedia.org/wiki/WTFPL )
Instructions:
Add the following bookmarklet to your browser:
javascript:(function(s)%7Bvar%20e%3Ddocument.createElement('script')%3Be.src%3Ds%3Bdocument.head.appendChild(e)%3B%7D)('https%3A%2F%2Fraw.github.com%2Fgist%2F2157849%2FHSBC.js')
Open this bookmarklet when you are looking at a previous statement or recent
transactions in HSBC personal online banking and it will bring up a CSV copy of
your transactions from that statement/list that you can copy to your clipboard
and paste into a file (e.g. to import into Xero or similar services).
Changelog:
v0.5 - Add AJAX fetching of a full year of statements.
v0.4.1 - Add status updates for AJAX fetches.
v0.4 - Add AJAX fetching of extra information for abbreviated transactions
v0.3 - Fix dates for accounts with Overdraft Limits
v0.2 - Adds support for recent transactions, fixes balance=0
v0.1 - initial release
Compatibility: only tested in Chrome 17 under Mac OS X against my own accounts.
Use at your own risk. Educational purposes only. Etc etc.
******************************/
var textarea = null;
var superarray = [];
var additionalPending = 0;
var statementPending = 0;
var errorOccurred = false;
var ascending = true;
var div = document.createElement('div');
var h1 = document.createElement('h1');
h1.innerText = "Double-click to dismiss";
//div.insertBefore(h1,div.firstChild);
div.appendChild(h1);
div.appendChild(document.createTextNode("Date, Transaction Type, Payee, Amount, Balance (GBP)"));
textarea = document.createElement('textarea');
textarea.style.width="100%";
textarea.style.height = "80%";
textarea.value = "If this message remains, then an error has occurred";
div.appendChild(textarea);
div.style.position="fixed";
div.style.top = "100px";
div.style.bottom = "100px";
div.style.border = "10px solid black";
div.style.borderRadius = "25px";
div.style.padding = "20px";
div.style.left = "100px";
div.style.right = "100px";
div.style.zIndex = "100";
div.style.backgroundColor = "white";
div.addEventListener('dblclick',function(e) {
div.parentNode.removeChild(div);
},false);
document.body.appendChild(div);
function checkFinished() {
if (errorOccurred) {
div.style.backgroundColor = "red";
}
if (additionalPending+statementPending == 0) {
done();
} else {
textarea.value = additionalPending+" additional info fetches remaining; "+statementPending+" statements fetches remaining...";
}
};
function done() {
superarray.reverse();
var results = [];
for (var j = 0; j < superarray.length; j++) {
var array = superarray[j];
if (!ascending) {
array.reverse();
}
for (var i = 0; i<array.length; i++) {
results.push(array[i].join(","));
}
}
csv = results.join("\n");
textarea.value = csv;
textarea.focus();
textarea.select();
}
function parseStatement(statement,$,$rootEl,array) {
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var previous = true;
var tmp = $rootEl.find("div .hsbcTextRight").first()[0].innerText.split(" ");
if (tmp.length > 4) {
tmp = $rootEl.find("div .extPibRow .extTableColumn2").eq(2)[0].innerText.split(" ");
previous = false;
}
var statementDay = parseInt(tmp[0].replace(/^0/,""));
var statementMonth = months.indexOf(tmp[1]);
var statementYear = parseInt(tmp[2]);
if (statementMonth == 0 && ascending) {
statementYear--;
}
var table = $rootEl.find(".containerMain table").eq(1);
var trs = table.find('tbody tr');
var currentMonth = statementMonth;
var currentBalance = 0;
for (var i = 0, l = trs.length; i<l; i++) {
var tr = trs.eq(i);
if (previous && (i == 0 || i == l-1)) {
currentBalance = parseFloat(tr.find('td')[5].innerText);
// Skip "Balance brought/carried forward" lines
continue;
}
(function(){
var row = [];
var tds = tr.find('td');
var amount = 0;
for (var j = 0, m = tds.length; j<m; j++) {
if (j >= 6) {
continue;
}
var td = tds[j];
var skip = false;
str = td.innerText;
if (!previous) {
var tmp = str.split("\n");
for (var k = 0; k < tmp.length; k++) {
tmp[k] = $.trim(tmp[k]);
}
str = tmp.join("\n");
str = str.replace(/\n\n/g,"\n");
}
str = str.replace(/[\v\0\r\t]/g," ");
str = str.replace(/(^ | (?= )| $)/g,"");
str = str.replace(/"/g,"\\\"");
str = $.trim(str);
str = str.replace(/\n/g, " | ");
if (j == 0) {
tmp = str.split(" ");
var day = parseInt(tmp[0].replace(/^0/,""));
var month = months.indexOf(tmp[1]);
if (currentMonth == 11 && month == 0) {
statementYear++;
}
currentMonth = month;
strMonth = ""+(month+1);
if (strMonth.length < 2) {
strMonth = "0"+strMonth;
}
strDay = ""+day;
if (strDay.length < 2) {
strDay = "0"+strDay;
}
str = ""+statementYear+"-"+strMonth+"-"+strDay;
}
if (j < 3) {
str = "\""+str+"\"";
if (j == 2) {
// AJAX fetch more details.
var a = tds.eq(j).find("a");
if (a && a.length) {
var href = a.attr("href");
console.log("Additional: "+statement+" :: "+a[0].innerText);
additionalPending++;
$.ajax({
url:href
}).done(function(data){
var a = data.indexOf("<strong>Additional details:</strong>");
if (a != -1) {
var relevant = data.substr(a,1000);
relevant = relevant.replace(/^[\s\S]*?<p>([\s\S]*?)<\/p>[\s\S]*$/,"$1");
relevant = relevant.replace(/<br \/>/g,"");
relevant = $.trim(relevant);
var tmp = relevant.split("\n");
for (var i = 0; i < tmp.length; i++) {
tmp[i] = $.trim(tmp[i]);
}
relevant = tmp.join("\n");
relevant = relevant.replace(/\n\n/g,"\n");
relevant = relevant.replace(/\n/g," | ");
row[2] = "\""+relevant+"\"";
console.log(relevant);
}
additionalPending--;
checkFinished();
});
}
}
} else {
str = parseFloat(str);
if (isNaN(str)) {
str = 0.0;
}
if (j == 3) {
amount -= str;
skip = true;
} else if (j == 4) {
amount += str;
str = amount;
} else if (j == 5) {
if (previous) {
if (str == 0.0) {
currentBalance = str = parseInt((currentBalance + amount)*100)/100;
} else {
currentBalance = str;
}
}
}
}
if (!skip) {
row.push(str);
}
}
array.push(row);
})();
}
checkFinished();
}
(function($){
var trs = $(".hsbcMainContent table.hsbcRowSeparator tr");
if (!trs || trs.length < 2) {
var array = [];
superarray.push(array);
parseStatement("Current Page", $, $(document.body), array);
} else {
for (var i = 1; i<trs.length; i++) {
(function(){
var a = trs.eq(i).find("td a").eq(0);
var href = a.attr("href");
var array = [];
superarray.push(array);
if (href && href.length) {
// Fetch it
statement = a[0].innerText;
console.log("Statement: "+statement);
statementPending++;
$.ajax({
url:href
}).done(function(data){
data = data.replace(/^[\s\S]*<body[^>]*>([\s\S]*)<\/body[\s\S]*$/,"$1");
var div = document.createElement('div');
div.innerHTML = data;
var $div = $(div);
parseStatement(statement, $, $div, array);
statementPending--;
checkFinished();
});
} else {
console.error("One of the links doesn't work!!");
errorOccurred = true;
}
})();
}
}
})(jQuery);
checkFinished();
@haveaguess

This comment has been minimized.

Copy link
Owner Author

commented Oct 8, 2016

use bookarmketlet javascript:(function(s)%7Bvar e%3Ddocument.createElement('script')%3Be.src%3Ds%3Bdocument.head.appendChild(e)%3B%7D)('https%3A%2F%2Fcdn.rawgit.com%2Fbenjie%2F2157849%2Fraw%2F59cede10a30f69d35d6b0d8900c83737c84cc3c5%2FHSBC.js')

@shuckster

This comment has been minimized.

Copy link

commented Jan 31, 2017

Hello! Just in case someone finds it useful I wrote a bookmarklet to download HSBC statements in CSV and other formats: http://shuckster.github.io/OBIS/

It can download a whole year of statements at once, and can follow the links inside a statement to get the description of each transaction, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.