Skip to content

Instantly share code, notes, and snippets.

@haveaguess
Forked from benjie/HSBC.js
Created October 8, 2016 19:52
Show Gist options
  • Save haveaguess/cda2cdbd5fbebc5819f05217cac11a2c to your computer and use it in GitHub Desktop.
Save haveaguess/cda2cdbd5fbebc5819f05217cac11a2c to your computer and use it in GitHub Desktop.
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
Copy link
Author

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
Copy link

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