Krótki skrypt do obróbki danych z pliku Excela

W bieżącym wpisie opiszę skrypt, który wczytuje dane z listy tankowań w nowszym formacie MS Excel – xlsx.

Skrypt sumuje zakupione paliwo w danym okresie, następnie wyświetla, jaką ilość paliwa zatankowano do poszczególnych pojazdów. W razie rozbieżności z danymi źródłowymi – kartami kierowcy, można wyświetlić szczegółową listę tankowań dla konkretnego pojazdu.

Katalog ze skryptem zawiera również podkatalog “Dane”, w którym umieszczam pliki kolejnych list tankowań.

W pliku Excela komórki pierwszego wiersza definiują nazwy poszczególnych kolumn z danymi m.in. “Ilość” – określa ile paliwa zatankowano podczas jednego tankowania, “Data” – określa datę tankowania, “Numer rejestracyjny” – zawiera numer rejestracyjny pojazdu.

Skrypt zawiera jedną klasę Reports, która zawiera dwie metody: __init__() oraz parser().

W metodzie __init__() określam kolejno katalog, w którym jest umieszczony skrypt main.py i wartość tą przypisuję do zmiennej script_dir. Następnie definiuję zmienną data_dir, która zawiera ścieżkę do podkatalogu “Dane”, który zawiera pliki *.xlsx z danymi. Z plików tych jest sporządzana lista plików, z której jest wybierany najnowszy plik. Dane z najnowszego pliku są wczytywane jako obiekt ramki pandas, który to jest przypisane jako atrybut klasy – zmienna self.df, dzięki czemu obiekt ten będzie dostępny także dla innych metod klasy, gdy metoda __init__() zakończy swoje działanie. Następnie jest wywoływana metoda parser().

W metodzie parser() na początku czyszczę terminal z poprzednich wpisów:

os.system('cls' if os.name == 'nt' else 'clear')

W zależności od systemu, na którym jest uruchamiany skrypt wykonywana jest komenda cls – dla Windows lub clear dla Linux lub MacOS.

Następnie definiuję dwie zmienne: f_date oraz l_date, które przechowują daty odpowiednio pierwszego i ostatniego tankowania na liście tankowań. W kolejnym wierszu wyświetlam nagłówek zestawienia, a następnie zamieniam znak przecinka z danych z kolumny “Ilość” – separatora części dziesiętnej na znak kropki.

Całe pobrane paliwo na wszystkie samochody obliczam za pomocą:

self.df['Ilość'].sum()

W nieskończonej pętli while pobieram tekst zawierający dowolny fragment numeru rejestracyjnego lub “/q” – wyjście za pomocą wywołania wyjątku SystemExit lub “/m” – powrót do głównego zestawienia za pomocą wywołania metody self.parser().

W pętli – for key, value in cars_group[‘Ilość’]: w kolejnych iteracjach sprawdzane jest, czy wybrany fragment tekstu wpisanego przez użytkownika (po zmianie na wielkie litery) jest obecny w numerze rejestracyjnym pojazdu. Jeśli powyższy warunek jest spełniony to zostają wyświetlone wszystkie daty i ilości tankowań. Oprócz wszystkich tankowań dla wybranego pojazdu, wyświetlane jest także podsumowanie zatankowanych litrów dla pojazdu.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
@ author: Sławomir Kwiatkowski
@ date: 2019.10.11
'''

import os
import glob
import pandas as pd


class Reports:
	
    def __init__(self):
        script_dir = os.path.dirname(os.path.abspath(__file__))
        data_dir = os.path.join(script_dir, 'Dane')
        list_of_files = glob.glob(os.path.join(data_dir, '*.xlsx'))
        latest_file = max(list_of_files, key=os.path.getctime)
        path_to_file = os.path.join(data_dir, latest_file)
        self.df = pd.read_excel(path_to_file)
        self.parser()

    
    def parser(self):
        os.system('cls' if os.name == 'nt' else 'clear')
        print()
        f_date = self.df['Data'].min()
        l_date = self.df['Data'].max()

        print('>>>Zestawienie paliwa za okres od {} do {}.{}.{}<<<'.format(f_date.day, 
        l_date.day, l_date.month, l_date.year))
        self.df['Ilość'] = self.df['Ilość'].astype(str)
        self.df['Ilość'] = self.df['Ilość'].str.replace(',', '.')
        self.df['Ilość'] = self.df['Ilość'].astype(float)
        print()
        print('>>>Zakup paliwa: ', self.df['Ilość'].sum())
        cars_group = self.df.groupby('Numer rejestracyjny')
        print()
        print(cars_group['Ilość'].sum())
        print()
        while True:
            choice = input('Podaj nr rej. pojazdu (lub /q-wyjście, /m-ekran główny):  ')
            os.system('cls' if os.name == 'nt' else 'clear')
            if choice == '/q': raise SystemExit
            if choice == '/m': self.parser()
            for key, value in cars_group['Ilość']:
                if choice.upper() in key:
                    print('>>>Tankowania dla pojazdu: ', key)
                    total = 0
                    for i, v in zip(value.index, value.values):
                        print(self.df.loc[i, 'Data'], v)
                        total +=v
                    print(f'>>>Suma tankowań dla {key}: {total} ltr')
                    print()


if __name__ == "__main__":
    reports = Reports()