示例#1
0
        public IEnumerable <PaymentModel> ScrapeStatement(ScraperConfigurationModel configuration, Chrome chromeDriver,
                                                          DateTime startFrom)
        {
            if (startFrom < DateTime.Now.AddYears(-2).AddDays(1))
            {
                startFrom = DateTime.Now.AddYears(-2).AddDays(1);
            }

            var driver = chromeDriver.Driver;

            Login(configuration, driver);

            var existingLinks = driver.FindElementsByPartialLinkText("История операций").ToList();

            var link1 = (RemoteWebElement)driver.FindElementByLinkText("Счета");

            driver.Mouse.MouseMove(link1.Coordinates, 1, 1);

            Thread.Sleep(500);

            existingLinks = driver.FindElementsByPartialLinkText("История операций").Except(existingLinks).ToList();
            existingLinks.Single().Click();

            Thread.Sleep(2000);

            var selectBtn = driver.FindElementById("pt1:soc1::button");

            var accountsChooser = driver.FindElementById("pt1:soc1::pop");

            var accs = accountsChooser.FindElements(By.TagName("tr"));

            var result = new List <PaymentModel>();

            foreach (var acc in accs)
            {
                var tds = acc.FindElements(By.TagName("td"));
                if (tds.Count < 4)
                {
                    continue;
                }

                selectBtn.Click();

                Thread.Sleep(2000);

                tds[0].Click();

                Thread.Sleep(2000);


                var inputDate = driver.FindElementById("pt1:id1::fd");
                inputDate.Click();

                Thread.Sleep(2000);

                driver.Keyboard.SendKeys(Enumerable.Repeat(Keys.Delete, 20).Join(""));
                Thread.Sleep(500);
                driver.Keyboard.SendKeys(Enumerable.Repeat(Keys.Backspace, 20).Join(""));
                Thread.Sleep(500);
                driver.Keyboard.SendKeys(Enumerable.Repeat(Keys.Delete, 20).Join(""));
                Thread.Sleep(500);
                driver.Keyboard.SendKeys(Enumerable.Repeat(Keys.Backspace, 20).Join(""));
                Thread.Sleep(500);
                driver.Keyboard.SendKeys(startFrom.ToString("ddMMyyyy"));

                var submit = driver.FindElementById("pt1:showButton::button");
                submit.Click();

                Thread.Sleep(2000);

                var csv = driver.FindElementById("pt1:downloadCSVLink");
                csv.Click();

                int waited = 0;
                while (chromeDriver.GetDownloads().Count < 1 && waited < 300)
                {
                    Thread.Sleep(1000);
                    waited++;
                }

                var files = chromeDriver.GetDownloads();
                if (files.Count == 1)
                {
                    var csvFile    = files.First();
                    var csvContent = File.ReadAllLines(csvFile.FullName, Encoding.GetEncoding(1251)).Skip(1).Select(v => new AlphaStatement(v)).ToList();
                    var payments   = csvContent.Select(v =>
                                                       Statement(v.Date, v.AccountName, v.What, v.Outcome - v.Income, v.Ccy, v.Reference)).ToList();

                    var holdPayments = payments.Where(v => v.StatementReference == "HOLD").ToList();
                    payments = payments.Except(holdPayments).ToList();

                    result.AddRange(payments);
                    csvFile.Delete();
                }

                chromeDriver.CleanupDownloads();
            }


            return(result);
        }
        public override IList <PaymentModel> ScrapeStatement(ScraperConfigurationModel configuration, Chrome chrome, DateTime startFrom)
        {
            var driver = chrome.Driver;

            Login(configuration, chrome);

            driver.Navigate().GoToUrl(@"https://online.raiffeisen.ru/#/history/statement");

            var accounts = GetElements(driver, By.TagName("c-select-option-account"));

            var link     = GetElements(driver, By.TagName("a")).First(v => v.GetAttribute("href")?.Contains("/transaction.ofx?") == true);
            var linkText = link.GetAttribute("href");

            var build = new Uri(linkText);

            var result = new List <PaymentModel>();

            var urlFormat = @"https://online.raiffeisen.ru/rest/account/{accountId}/transaction.ofx?from={from}&to={to}&sort=date&order=desc&access_token={token}";

            var originalQuery = QueryHelpers.ParseQuery(build.Query);

            var accessToken = originalQuery["access_token"].First();

            var accountDetails = accounts.Select(v =>
            {
                var id          = v.FindElement(By.TagName("div")).GetAttribute("data-account-id");
                var textElement = v.FindElement(By.TagName("account-logo")).FindElement(By.XPath(".."));
                var name        = textElement.GetAttribute("textContent").Trim();
                return(id, name);
            }).Distinct().ToList();

            Logger.LogInformation($"Found {accountDetails.Count} Raiffeisen accounts");

            foreach (var account in accountDetails)
            {
                var accountId   = account.id;
                var accountName = account.name;
                var url         = urlFormat.Replace("{accountId}", accountId)
                                  .Replace("{from}", startFrom.ToString("yyyy-MM-ddTHH:mm"))
                                  .Replace("{to}", DateTime.Now.ToString("yyyy-MM-ddTHH:mm"))
                                  .Replace("{token}", accessToken);

                // Raiffeisen sometimes doesn't return all payments on first call
                for (int i = 0; i < 3; i++)
                {
                    driver.Navigate().GoToUrl(url);

                    Logger.LogInformation($"Getting statement for {account.name} at {url}, attempt {i}");

                    int waited = 0;
                    while (chrome.GetDownloads().Count < 1 && waited < 300)
                    {
                        WaitForPageLoad(driver);
                        waited++;
                    }

                    Thread.Sleep(10000);

                    var files = chrome.GetDownloads();
                    if (files.Count == 1)
                    {
                        var ofxFile = files.First();

                        var doc = File.ReadAllText(ofxFile.FullName);

                        var xdoc = XDocument.Parse(doc);

                        var statements =
                            xdoc.XPathSelectElements("OFX/BANKMSGSRSV1/STMTTRNRS/STMTRS/BANKTRANLIST/STMTTRN");

                        var ccyNode = xdoc.XPathSelectElement("OFX/BANKMSGSRSV1/STMTTRNRS/STMTRS/CURDEF");

                        var ccy = ccyNode.Value;

                        var payments = new List <PaymentModel>();

                        foreach (var st in statements)
                        {
                            var timeStr   = st.Element("DTPOSTED").Value;
                            var time      = DateTime.ParseExact(timeStr, "yyyyMMddhhmmss", CultureInfo.CurrentCulture);
                            var amountStr = st.Element("TRNAMT").Value;
                            var amount    = double.Parse(amountStr,
                                                         new NumberFormatInfo {
                                NumberDecimalSeparator = "."
                            });
                            var name = st.Element("MEMO").Value;

                            var id = timeStr + amountStr + name;

                            int counter = 0;
                            while (payments.Any(j => j.StatementReference == id))
                            {
                                id = timeStr + amountStr + name + counter++;
                            }

                            var kind = amount < 0 ? PaymentKind.Expense : PaymentKind.Income;

                            var stmt = Statement(time, accountName, name, amount, kind, ccy, id);
                            payments.Add(stmt);
                        }

                        Logger.LogInformation($"Got {payments.Count} payments from {url}, attempt {i}");
                        result.AddRange(payments);
                        ofxFile.Delete();
                    }
                }
            }

            var oldCount = result.Count;

            result = result.GroupBy(v => v.StatementReference).Select(v => v.First()).ToList();
            Logger.LogInformation($"Deduplicated payments {oldCount} -> {result.Count}");

            return(result);
        }
        public override IList <MoneyStateModel> Scrape(ScraperConfigurationModel configuration, Chrome chrome)
        {
            var driver = chrome.Driver;

            driver.Navigate().GoToUrl("https://lk.alfadirect.ru/");

            var fields = GetElements(driver, By.TagName("input")).ToList();
            var name   = fields[0];
            var pass   = fields[1];

            name.Click();
            chrome.SendKeys(configuration.Login);
            pass.Click();
            chrome.SendKeys(configuration.Password);

            chrome.SendKeys(Keys.Return);
            WaitForPageLoad(driver);
            driver.Navigate().GoToUrl("https://lk.alfadirect.ru/reports/MyPortfolio");
            WaitForPageLoad(driver);

            var lnk = GetElement(driver, By.LinkText("Просмотреть"));

            var link = lnk.GetAttribute("href");

            link = link.Replace("HTML", "XML");

            driver.Navigate().GoToUrl(link);

            int waited = 0;

            while (chrome.GetDownloads().Count < 1 && waited < 300)
            {
                WaitForPageLoad(driver);
                waited++;
            }

            var file = chrome.GetDownloads()[0].FullName;

            var contents = File.ReadAllText(file);

            var xDoc = XDocument.Parse(contents);

            var el = xDoc.Root;

            el = el.Element(XName.Get("Financial_results", "MyPortfolio"));
            el = el.Element(XName.Get("Report", "MyPortfolio"));
            var positions = el.Descendants(XName.Get("Details", "MyPortfolio")).ToList();

            var result = new List <MoneyStateModel>();

            foreach (var item in positions)
            {
                var ccy        = item.Attribute("code_curr")?.Value;
                var activeType = item.Attribute("active_type")?.Value;
                var activeName = item.Attributes().FirstOrDefault(s =>
                                                                  s.Name.LocalName.StartsWith("p_name") && !string.IsNullOrWhiteSpace(s.Value))?.Value;

                var activeCurrentPrice = item.Attribute("CostOpenPosEnd8")?.Value;

                if (!double.TryParse(activeCurrentPrice, NumberStyles.Any, new NumberFormatInfo {
                    NumberDecimalSeparator = "."
                }, out var amount))
                {
                    continue;
                }

                result.Add(Money(activeName ?? (activeType + " " + ccy), amount, ccy));
            }

            var totals = result.GroupBy(v => v.Ccy).Select(s => Money("Итого " + s.Key, s.Sum(v => v.Amount), s.Key)).ToList();

            result.AddRange(totals);
            return(result);
        }
示例#4
0
        public override IList <PaymentModel> ScrapeStatement(ScraperConfigurationModel configuration, Chrome chrome, DateTime startFrom)
        {
            DoLogin(configuration, chrome);

            var driver = chrome.Driver;

            var btns = GetElements(driver, By.TagName("button"));

            var rightBtn = btns.First(s => s.Text.ToLower().Contains("выписка"));

            rightBtn.Click();

            var form = GetElement(driver, By.ClassName("address_form"));

            var switches = form.FindElements(By.ClassName("switch_item"));

            var htmlSwitch = switches.First(s => s.Text == "1C");

            htmlSwitch.Click();

            var rows = form.FindElements(By.ClassName("form_group"));

            var periodRow    = rows.First(v => v.Text.ToLower().Contains("за период:"));
            var periodButton = periodRow.FindElement(By.TagName("button"));

            periodButton.Click();

            var dateSelector = GetElement(driver, By.ClassName("filter_date_value"));
            var inputs       = dateSelector.FindElements(By.TagName("input"));
            var first        = inputs.First();

            first.Click();

            first.SendKeys(Keys.Control + "a");
            first.SendKeys(Keys.Delete);
            first.SendKeys(startFrom.ToString("dd.MM.yyyy"));
            first.SendKeys(Keys.Enter);

            var dateSelectorApply = dateSelector.FindElement(By.TagName("button"));

            dateSelectorApply.Click();

            var buttons  = form.FindElements(By.TagName("button"));
            var dlButton = buttons.First(s => s.Text.ToLower().Contains("получить"));

            chrome.CleanupDownloads();

            dlButton.Click();

            var waited = 0;

            while (chrome.GetDownloads().Count == 0 && waited < 300)
            {
                WaitForPageLoad(driver);
                waited++;
            }

            var dlItem = chrome.GetDownloads().First().FullName;

            var docs = ParseOdinAssFile(dlItem);

            var config = docs.Single(v => !v.ContainsKey("СекцияДокумент"));

            var account = config["РасчСчет"];

            var goodDocs = docs.Where(v => v.ContainsKey("СекцияДокумент"));

            var statements = goodDocs.Select(v =>
            {
                var whenString = v["Дата"];
                var when       = DateTime.ParseExact(whenString, "dd.MM.yyyy", CultureInfo.InvariantCulture);
                var what       = v["НазначениеПлатежа"];
                var amountText = v["Сумма"];
                var amount     = double.Parse(amountText, new NumberFormatInfo()
                {
                    NumberDecimalSeparator = "."
                });

                var isIncome  = v["ПолучательСчет"] == account;
                var kind      = isIncome ? PaymentKind.Income : PaymentKind.Expense;
                var ccy       = "RUB";
                var reference = v["Номер"];

                return(Statement(when, account, what, amount, kind, ccy, reference));
            }).ToList();

            return(statements);
        }
示例#5
0
        public override IList <PaymentModel> ScrapeStatement(ScraperConfigurationModel configuration, Chrome chrome, DateTime startFrom)
        {
            var driver = chrome.Driver;

            Login(configuration, chrome);

            driver.Navigate().GoToUrl(@"https://online.raiffeisen.ru/#/history/statement");

            var accounts = GetElements(driver, By.TagName("c-select-option-account"));

            var link     = GetElements(driver, By.TagName("a")).First(v => v.GetAttribute("href")?.Contains("/transaction.ofx?") == true);
            var linkText = link.GetAttribute("href");

            var build = new Uri(linkText);

            var result = new List <PaymentModel>();

            var urlFormat = @"https://online.raiffeisen.ru/rest/account/{accountId}/transaction.ofx?from={from}&to={to}&sort=date&order=desc&access_token={token}";

            var originalQuery = QueryHelpers.ParseQuery(build.Query);

            var accessToken = originalQuery["access_token"].First();

            var accountDetails = accounts.Select(v =>
            {
                var id          = v.FindElement(By.TagName("div")).GetAttribute("data-account-id");
                var textElement = v.FindElement(By.TagName("account-logo")).FindElement(By.XPath(".."));
                var name        = textElement.GetAttribute("textContent").Trim();
                return(id, name);
            }).Distinct().ToList();

            Logger.LogInformation($"Found {accountDetails.Count} Raiffeisen accounts");

            foreach (var account in accountDetails)
            {
                var accountId   = account.id;
                var accountName = account.name;
                var url         = urlFormat.Replace("{accountId}", accountId)
                                  .Replace("{from}", startFrom.ToString("yyyy-MM-ddTHH:mm"))
                                  .Replace("{to}", DateTime.Now.ToString("yyyy-MM-ddTHH:mm"))
                                  .Replace("{token}", accessToken);

                // Raiffeisen sometimes doesn't return all payments on first call
                for (int i = 0; i < 3; i++)
                {
                    driver.Navigate().GoToUrl(url);

                    Logger.LogInformation($"Getting statement for {account.name} at {url}, attempt {i}");

                    int waited = 0;
                    while (chrome.GetDownloads().Count < 1 && waited < 300)
                    {
                        WaitForPageLoad(driver);
                        waited++;
                    }

                    Thread.Sleep(10000);

                    var files = chrome.GetDownloads();
                    if (files.Count == 1)
                    {
                        var ofxFile = files.First();

                        var doc = File.ReadAllText(ofxFile.FullName);

                        var xdoc = XDocument.Parse(doc);

                        var payments = ParseOfx(xdoc, accountName);

                        Logger.LogInformation($"Got {payments.Count} payments from {url}, attempt {i}");
                        result.AddRange(payments);
                        ofxFile.Delete();
                    }
                }
            }

            var oldCount = result.Count;

            result = result.GroupBy(v => v.StatementReference).Select(v => v.First()).ToList();
            Logger.LogInformation($"Deduplicated payments {oldCount} -> {result.Count}");

            return(result);
        }
        public override IList <PaymentModel> ScrapeStatement(ScraperConfigurationModel configuration, Chrome chromeDriver,
                                                             DateTime startFrom)
        {
            if (startFrom < DateTime.Now.AddYears(-2).AddDays(1))
            {
                startFrom = DateTime.Now.AddYears(-2).AddDays(1);
            }

            var driver = chromeDriver.Driver;

            Login(configuration, chromeDriver);

            var unixTime  = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            var startTime = (long)(startFrom - unixTime).TotalMilliseconds;
            var endTime   = (long)(DateTime.UtcNow - unixTime).TotalMilliseconds;
            var cardId    = 0;

            var sessionId = driver.Manage().Cookies.GetCookieNamed("psid").Value;

            var links         = GetElements(driver, By.TagName("a")).ToList();
            var matchingLinks = links.Where(v => v.GetProperty("href").Contains("/events/account/")).ToList();

            var result = new List <PaymentModel>();

            var accountRegex = new Regex(@"\/events\/account\/([^\/]+)\/(?<accountId>[0-9]+)");

            foreach (var link in matchingLinks)
            {
                var href = link.GetAttribute("href");
                if (href == null)
                {
                    continue;
                }

                var match = accountRegex.Match(href);
                if (match.Success)
                {
                    var children    = link.FindElements(By.TagName("div"));
                    var name        = children.First(v => v.GetAttribute("class").Contains("Item__name"));
                    var accountName = name.Text;

                    var accountId = match.Groups["accountId"].Value;

                    var url = $"https://www.tinkoff.ru/api/common/v1/export_operations/?format=ofx&sessionid={sessionId}&start={startTime}&end={endTime}&card={cardId}&account={accountId}";

                    driver.Navigate().GoToUrl(url);

                    int waited = 0;
                    while (chromeDriver.GetDownloads().Count < 1 && waited < 300)
                    {
                        WaitForPageLoad(driver);
                        waited++;
                    }

                    var file = chromeDriver.GetDownloads()[0].FullName;

                    var contents = File.ReadAllText(file);
                    var ofx      = XDocument.Parse(contents);
                    var payments = ParseOfx(ofx, accountName);
                    result.AddRange(payments);
                    File.Delete(file);
                }
            }

            return(result);
        }