Last active
April 2, 2024 18:28
-
-
Save Ebonsignori/005a6aed68c324f0244bb47fd06691b8 to your computer and use it in GitHub Desktop.
Scrape SOFI transactions
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
/* | |
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