Skip to content

Instantly share code, notes, and snippets.

@fulcrum6378
Created January 10, 2022 20:02
Show Gist options
  • Save fulcrum6378/0180e4882addb1f24d4834cf27f9a641 to your computer and use it in GitHub Desktop.
Save fulcrum6378/0180e4882addb1f24d4834cf27f9a641 to your computer and use it in GitHub Desktop.
Analyze transaction messages from bank Mellat, exported by Telexporter to HTML
import matplotlib.pyplot as plt
import os.path
import re
import sys
from bs4 import BeautifulSoup
from datetime import datetime
from persiantools.jdatetime import JalaliDateTime
from pytz import timezone
from typing import List
tz = timezone('Asia/Tehran')
class Message:
def __init__(self, text: str, date: str, time: str):
self.text = text
self.date = date
self.time = time
self.jalali = self.gregory = datetime.fromtimestamp(0, tz=tz)
if date != "" and time != "":
century = "13" if int(date[:2]) > 50 else "14"
splTime = time.split(":")
self.jalali = JalaliDateTime(int(century + date[:2]), int(date[3:5]), int(date[6:8]),
int(splTime[0]), int(splTime[1]),
tzinfo=tz)
self.gregory = self.jalali.to_gregorian()
class Transaction(Message):
def __init__(self, text: str, amount: str, remain: str, date: str, time: str):
Message.__init__(self, text, date, time)
self.amount = int(amount.replace(",", "")) if isinstance(amount, str) else amount
self.remain = int(remain.replace(",", "")) if isinstance(remain, str) else remain
# self.amount /= 220000
# self.remain /= 220000
class Income(Transaction):
def __init__(self, text: str, amount: str, remain: str, date: str, time: str):
Transaction.__init__(self, text, amount, remain, date, time)
class Expense(Transaction):
def __init__(self, text: str, amount: str, remain: str, date: str, time: str):
Transaction.__init__(self, text, amount, remain, date, time)
root = os.path.dirname(os.path.realpath(__file__)) + "/"
incomes: List[Transaction] = list()
expenses: List[Transaction] = list()
twoFactor, bullshit = list(), list()
for html in sys.argv[1:]:
with open(root + html, "r", encoding="utf-8") as f:
soup = BeautifulSoup(f.read(), 'html.parser')
every = soup.find_all('div', attrs={'class': 'message'})
for e in every:
e = str(e)[21:-6].strip()
bTime, eTime = re.search(r'<p class="time">', e), re.search(r'</p>', e)
sTime = e[bTime.end():eTime.start()]
sDate = ""
if "واريز به حساب" in e:
bAmo, eAmo = re.search(r"مبلغ : ", e), re.search(r" ريال", e)
bRem = re.search(r"موجودي : ", e)
bRem = bRem if bRem is not None else re.search(r"موجودي: ", e)
bDat = re.search(r"99/", e)
bDat = bDat if bDat is not None else re.search(r"00/", e)
if bAmo is not None and eAmo is not None and bRem is not None and bDat is not None:
incomes.append(Income(e, e[bAmo.end():eAmo.start()],
e[bRem.end():bRem.end() + re.search(r" ريال", e[bRem.end():]).start()],
e[bDat.start():bDat.start() + 8], sTime))
else:
bullshit.append(Message(e, sDate, sTime))
elif "برداشت از حساب" in e:
bAmo, eAmo = re.search(r"مبلغ : ", e), re.search(r" ريال", e)
bRem = re.search(r"موجودي : ", e)
bRem = bRem if bRem is not None else re.search(r"موجودي: ", e)
bDat = re.search(r"99/", e)
bDat = bDat if bDat is not None else re.search(r"00/", e)
if bAmo is not None and eAmo is not None and bRem is not None and bDat is not None:
expenses.append(Expense(e, e[bAmo.end():eAmo.start()],
e[bRem.end():bRem.end() + re.search(r" ريال", e[bRem.end():]).start()],
e[bDat.start():bDat.start() + 8], sTime))
else:
bullshit.append(Message(e, sDate, sTime))
elif "رمز برداشت وجه از کارت شما" in e or "رمز پويا" in e:
twoFactor.append(Message(e, sDate, sTime))
elif " سود " in e:
interest = Income(e, e[re.search(r"به مبلغ ", e).end():re.search(r" واريز", e).start()],
incomes[-1].remain if len(incomes) > 1 else "-1", sDate, sTime)
interest.remain += interest.amount
incomes.append(interest)
else:
bullshit.append(Message(e, sDate, sTime))
print("INCOME MESSAGES:", len(incomes))
print("EXPENSE MESSAGES:", len(expenses))
print("TWO-FACTOR MESSAGES:", len(twoFactor))
print("BULLSHIT MESSAGES:", len(bullshit))
print()
all_transactions = incomes + expenses
valid_tas = list()
for t in all_transactions:
if t.gregory.year != 1970:
valid_tas.append(t)
valid_tas.sort(key=lambda k: k.gregory)
initial = None
if isinstance(valid_tas[0], Income):
initial = valid_tas[0].remain - valid_tas[0].amount
else:
initial = valid_tas[0].remain + valid_tas[0].amount
print("INITIAL:", '{:,}'.format(initial))
print("INCOME:", '{:,}'.format(sum([x.amount for x in incomes])))
print("EXPENSE:", '{:,}'.format(sum([x.amount for x in expenses])))
print("IN", valid_tas[-1].gregory - valid_tas[0].gregory)
print()
while True:
to_show = input("SHOW WHAT? (b => Balance, e => Expenses, i => Incomes, q => Quit):\n")
transactions = list()
if to_show == "b":
transactions = all_transactions
elif to_show == "e":
transactions = expenses
elif to_show == "i":
transactions = incomes
else:
quit()
transactions.sort(key=lambda k: k.gregory)
rems, tims = list(), list()
for t in transactions:
if t.gregory.year == 1970:
continue
if to_show == "e" or to_show == "i":
rems.append(t.amount)
else:
rems.append(t.remain)
tims.append(t.gregory)
plt.plot(tims, rems)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment