Skip to content

Instantly share code, notes, and snippets.

@Ebonsignori
Last active April 2, 2024 18:28
Show Gist options
  • Save Ebonsignori/005a6aed68c324f0244bb47fd06691b8 to your computer and use it in GitHub Desktop.
Save Ebonsignori/005a6aed68c324f0244bb47fd06691b8 to your computer and use it in GitHub Desktop.
Scrape SOFI transactions
/*
Run on your Sofi Credit Card transactions page to scrape transactions into a CSV that can be copied into your Tiller Spreadsheet's "Transactions" page\
You may need to scroll to bottom and load more to get older transactions
*/
// Script will gather transactions until this date in Month-Day-Year format
const getUntilDate = "01/05/2024"
const lastTrx = "Tom mccall waterfront - 03/06/2024" // Use this for manually figuring out where to set `getUntilDate` in the future
// Whatever you want to show up for "Account #"
const accountNumber = "xxxx1234"
// Sofi account name (name you want to use under "Account" in transaction)
const account = "Credit Card"
// Whatever you want to show up for "Institution"
const institution = "SoFi"
const untilDate = new Date(getUntilDate)
const today = new Date()
for (const h3 of document.querySelectorAll("h3")) {
if (h3.textContent.trim() === "Transactions") {
const txContainer = h3.parentNode.parentNode.children[1]
// Pending, pending tx list, posted tx list
if (txContainer.children.length === 3) {
getTransactionsFromDiv(txContainer.children[2])
}
}
}
function getTransactionsFromDiv(parent) {
const transactions = []
for (const child of parent.children) {
// Skip anything that isn't a trx list container
if (child?.children?.[0].nodeName !== "DIV") {
continue;
}
// Loop over trx list
for (const item of child?.children) {
// Skip anything that isn't a trx
if (item?.children?.[0]?.children?.[0].nodeName !== "BUTTON") {
continue;
}
const itemWrapper = item?.children?.[0]?.children?.[0]?.children?.[0]?.children?.[0]?.children?.[0]?.children
const descAmountContainer = itemWrapper?.[0]
const trxDate = new Date(itemWrapper?.[1]?.textContent)
if (trxDate.getTime() < untilDate.getTime()) {
continue;
}
const description = descAmountContainer?.children?.[0]?.textContent
let amount = descAmountContainer?.children?.[1]?.textContent.replaceAll("$", "").replaceAll(",", "")
if (amount.startsWith("-")) {
amount = amount.substring(1);
} else {
amount = `-${amount}`
}
const month = `${trxDate.getMonth() + 1}/1/${getShortYear(trxDate)}`
const trxMonday = getMonday(trxDate)
const week = `${trxMonday.getMonth() + 1}/${trxMonday.getDate()}/${getShortYear(trxMonday)}`
const dateAdded = `${today.getMonth() + 1}/${today.getDate()}/${getShortYear(today)}`
transactions.push([
`${trxDate.getMonth() + 1}/${trxDate.getDate()}/${trxDate.getFullYear()}`,
description,
"", // Category
amount,
account,
accountNumber,
institution,
month,
week,
"", // Transaction ID. You can modify this script to expand each trx and get the number, but this isn't usefulf for me
"", // Account ID (used internally by Tiller)
"", // Check Number
description,
dateAdded
])
}
}
console.log(arrayToCSV(transactions))
}
function getMonday(d) {
d = new Date(d);
var day = d.getDay(),
diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
return new Date(d.setDate(diff));
}
function getShortYear(d) {
return d.getFullYear().toString().substr(2)
}
function arrayToCSV(arr, delimiter = ',') {
return arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join('\n');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment