Created
September 2, 2025 04:21
-
-
Save altbodhi/8725ab50192b280b3e893584df4984f9 to your computer and use it in GitHub Desktop.
Парсер выписки по счету из приложения Сбер Онлайн (pdf)
This file contains hidden or 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
| #r "nuget: FSharp.Data" | |
| open FSharp.Data | |
| open System | |
| type AccountTransaction = | |
| { Date: DateTime | |
| Category: string | |
| Amount: decimal | |
| Description: string } | |
| [<Literal>] | |
| let end_mark = "****0000" // ! <- исправить на цифры из pdf (номер карты) | |
| (* | |
| запросить выписку в сбер онлайн | |
| открыть в Libre Office Draw и | |
| сохранить как fodg под именем sber.fodg в папку с этим скриптом | |
| запустить скрипт командой dotnet fsi SberAccountParser.fsx | |
| (скачать среду NET можно по адресу https://dot.net) | |
| открыть полученный файл transactions.csv в Libre Calc | |
| *) | |
| type AccountStatementOpenDocument = XmlProvider<"sber.fodg"> | |
| let doc = AccountStatementOpenDocument.GetSample() | |
| let text = | |
| query { | |
| for page in doc.Body.Drawing.Pages do | |
| for frame in page.Frames do | |
| let item = | |
| match frame.TextBox with | |
| | Some t -> t.P.XElement.Value | |
| | None -> "" | |
| yield item | |
| } | |
| |> Seq.filter (String.IsNullOrWhiteSpace >> not) | |
| |> Seq.reduce (fun x e -> x + ";" + e) | |
| let items = text.Split end_mark | |
| let dec (s: string) = | |
| match Decimal.TryParse s with | |
| | true, v -> if s.StartsWith "+" then Ok v else Ok -v | |
| | _ -> Error $"<{s}> not number" | |
| let parse_desc (s: string) = | |
| let items = s.Split " Операция" | |
| items[0].Trim() | |
| let parse (s: string) = | |
| let terms = s.Split(";", StringSplitOptions.RemoveEmptyEntries) | |
| let zero = terms[0] | |
| match DateTime.TryParse zero with | |
| | true, v -> | |
| let name = terms[3] | |
| match dec terms[4] with | |
| | Ok amount -> | |
| Ok | |
| { Date = v | |
| Amount = amount | |
| Category = name | |
| Description = parse_desc terms[7] } | |
| | Error e -> Error e | |
| | _ -> Error $"<{zero}> not datetime" | |
| let transactions = | |
| items |> Array.map parse |> Array.filter _.IsOk |> Array.map (fun (Ok tx) -> tx) | |
| let save_as_csv (items: array<AccountTransaction>) path = | |
| let lines = Array.create<string> (items.Length + 1) "" | |
| lines.[0] <- "Год;Месяц;Дата;Операция;Сумма;Категория" | |
| for i = 0 to items.Length - 1 do | |
| let e = items[i] | |
| lines[i + 1] <- | |
| $"""{e.Date.Year};{e.Date.ToString("MMMM")};{e.Date.ToString "yyyy-MM-dd"};{e.Description};{e.Amount};{e.Category}""" | |
| IO.File.WriteAllLines(path, lines) | |
| let card_num = end_mark.Replace("*","") | |
| save_as_csv transactions (IO.Path.Combine(__SOURCE_DIRECTORY__, $"transactions_{card_num}.csv")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment