-
-
Save paulmist/6244473 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************** | |
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(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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 memo-links inside the individual statements to get the description of each transaction, too.