Created
January 10, 2022 20:02
-
-
Save fulcrum6378/0180e4882addb1f24d4834cf27f9a641 to your computer and use it in GitHub Desktop.
Analyze transaction messages from bank Mellat, exported by Telexporter to HTML
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
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