// сложный метод, в ходе которого мы вытаскиваем данные по финансовым показателям financialData с gurufocus.com
        public string GetFinancials(string ticker)
        {
            WebPage page             = GetWebPage($"https://www.gurufocus.com/financials/{ticker}");
            int     numberOfQuarters = 5;
            int     numberOfYears    = 4;
            int     quarterlyOffset  = 6;
            int     yearOffset       = 1;

            var finYearGurufocusModel  = new FinYearGurufocusModel();
            var finQuartGurufocusModel = new FinQuartGurufocusModel();

            var tdFiscalPer = page.Html.CssSelect("td").FirstOrDefault(x => x.Attributes["title"]?.Value == "Fiscal Period");

            if (tdFiscalPer != null)
            {
                var trFiscPer       = tdFiscalPer.ParentNode;
                var tdFiscalPeriods = trFiscPer.CssSelect("td").Where(x => x.Attributes["title"]?.Value != null);

                // вытаскиваем квартальные даты
                var quarters = new string[numberOfQuarters];
                for (int i = 0; i < quarters.Length; i++)
                {
                    string dateQuarterly = tdFiscalPeriods.ToList()[i + quarterlyOffset]?.GetAttributeValue("title", "");
                    dateQuarterly = dateQuarterly.Substring(0, 5); // берем первые 5 символов (MMMyy), т.к. только они значащие
                    string monthQuart = DateTime.ParseExact(dateQuarterly, "MMMyy", CultureInfo.InvariantCulture).Month.ToString();
                    string yearQuart  = DateTime.ParseExact(dateQuarterly, "MMMyy", CultureInfo.InvariantCulture).Year.ToString();
                    quarters[i] = monthQuart + "/" + yearQuart;
                }
                finQuartGurufocusModel.Quarterly = quarters;

                // берем первый период, чтобы знать с какого года вести отсчет (всего можем предоставить данные за 4 года)
                string startDate = tdFiscalPeriods.ToList()[yearOffset].GetAttributeValue("title", "");
                finYearGurufocusModel.startYear = DateTime.ParseExact(startDate, "MMMyy", CultureInfo.InvariantCulture).Year;
            }

            bool noMarketableSecurities = false;

            foreach (var param in financialData)
            {
                var tds     = page.Html.CssSelect("td");
                var tdParam = tds.FirstOrDefault(x => x.Attributes["title"]?.Value == param);
                if (tdParam != null)
                {
                    var trParam = tdParam.ParentNode;
                    List <HtmlAgilityPack.HtmlNode> listValues = trParam
                                                                 .CssSelect("td")
                                                                 .Where(x => x.Attributes["title"]?.Value != null)
                                                                 .ToList();

                    var dYearValues  = new double[numberOfYears];
                    var dQuartValues = new double[numberOfQuarters];
                    var style        = NumberStyles.Number | NumberStyles.AllowCurrencySymbol;
                    var culture      = new CultureInfo("en-GB");
                    // заполняем годовые данные
                    for (int i = 0; i < numberOfYears; i++)
                    {
                        Double.TryParse(
                            listValues[i + yearOffset].Attributes["title"].Value,
                            style,
                            culture,
                            out dYearValues[i]);
                    }
                    // заполняем квартальные данные
                    for (int i = 0; i < numberOfQuarters; i++)
                    {
                        // здесь смещение для получения квартальных данных уже должно быть на 1 меньше,
                        // т.к. показатель TTM в listValues уже не попадает (см. ссылку на gurufocus и разбирай таблицу)
                        Double.TryParse(
                            listValues[i + (quarterlyOffset - 1)].Attributes["title"].Value,
                            style,
                            culture,
                            out dQuartValues[i]);
                    }

                    // округляем все данные до 1 знака после запятой
                    dYearValues  = dYearValues.Select(d => Math.Round(d, 1)).ToArray();
                    dQuartValues = dQuartValues.Select(d => Math.Round(d, 1)).ToArray();

                    // копируем ссылки на получившиеся массивы с данными в соответствующие поля моделей
                    switch (param)
                    {
                    case "Revenue":
                        finYearGurufocusModel.RevenueData  = dYearValues;
                        finQuartGurufocusModel.RevenueData = dQuartValues;
                        break;

                    case "Net Income":
                        finYearGurufocusModel.IncomeData  = dYearValues;
                        finQuartGurufocusModel.IncomeData = dQuartValues;
                        break;

                    case "Cash, Cash Equivalents, Marketable Securities":
                        finYearGurufocusModel.CashData  = dYearValues;
                        finQuartGurufocusModel.CashData = dQuartValues;
                        break;

                    case "Cash and cash equivalents":
                        // для некоторых акций "Cash, Cash Equivalents, Marketable Securities" отсутствует,
                        // в таких случаях CashData формируется путем сложения "Cash and cash equivalents" с "Short-term investments"
                        if (finYearGurufocusModel.CashData == null)
                        {
                            finYearGurufocusModel.CashData  = dYearValues;
                            finQuartGurufocusModel.CashData = dQuartValues;
                            noMarketableSecurities          = true;
                        }
                        break;

                    case "Short-term investments":
                        if (noMarketableSecurities)
                        {
                            for (int i = 0; i < numberOfYears; i++)
                            {
                                finYearGurufocusModel.CashData[i]  += dYearValues[i];
                                finQuartGurufocusModel.CashData[i] += dQuartValues[i];
                            }
                            // записываем данные последнего квартала
                            finQuartGurufocusModel.CashData[numberOfQuarters - 1] += dQuartValues[numberOfQuarters - 1];
                        }
                        break;

                    case "Long-Term Debt & Capital Lease Obligation":
                        // показатель DebtData формируется путем сложения
                        // "Long-Term Debt & Capital Lease Obligation" с "Short-Term Debt & Capital Lease Obligation"
                        finYearGurufocusModel.DebtData  = dYearValues;
                        finQuartGurufocusModel.DebtData = dQuartValues;
                        break;

                    case "Short-Term Debt & Capital Lease Obligation":
                        for (int i = 0; i < numberOfYears; i++)
                        {
                            finYearGurufocusModel.DebtData[i]  += dYearValues[i];
                            finQuartGurufocusModel.DebtData[i] += dQuartValues[i];
                        }
                        // записываем данные последнего квартала
                        finQuartGurufocusModel.DebtData[numberOfQuarters - 1] += dQuartValues[numberOfQuarters - 1];
                        break;
                    }
                }
            }
            string result = string.Empty;
            JsonSerializerOptions jsonOptions = new JsonSerializerOptions
            {
                WriteIndented = true,
                Encoder       = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };

            result = "{\"yearData\":" + JsonSerializer.Serialize <FinYearGurufocusModel>(finYearGurufocusModel, jsonOptions) +
                     "," + "\"quarterlyData\":" + JsonSerializer.Serialize <FinQuartGurufocusModel>(finQuartGurufocusModel, jsonOptions) + "}";
            return(result);
        }
        public IActionResult GetFinancials(string ticker)
        {
            ScrapingBrowser browser = new ScrapingBrowser();
            WebPage         page;

            try
            {
                page = browser.NavigateToPage(new Uri($"https://www.gurufocus.com/financials/{ticker}"));
            }
            catch
            {
                return(BadRequest());
            }
            string[] financialData = new string[] { "Revenue", "Net Income", "Cash, Cash Equivalents, Marketable Securities",
                                                    "Cash and cash equivalents", "Short-term investments", "Long-Term Debt & Capital Lease Obligation", "Short-Term Debt & Capital Lease Obligation" };
            FinYearGurufocusModel  finYearGurufocusModel  = new FinYearGurufocusModel();
            FinQuartGurufocusModel finQuartGurufocusModel = new FinQuartGurufocusModel();

            var tdFiscalPer = page.Html.CssSelect("td").FirstOrDefault(x => x.Attributes["title"]?.Value == "Fiscal Period");

            if (tdFiscalPer != null)
            {
                var trFiscPer       = tdFiscalPer.ParentNode;
                var tdFiscalperiods = trFiscPer.CssSelect("td").Where(x => x.Attributes["title"]?.Value != null);

                // вытаскиваем кварталы
                string[] quarters = new string [5];
                for (int i = 0; i < quarters.Length; i++)
                {
                    string dateQuarterly = tdFiscalperiods.ToList()[i + 6]?.GetAttributeValue("title", "");
                    dateQuarterly = dateQuarterly.Substring(0, 5); // берем первые 5 символов (MMMyy), т.к. только они значащие
                    string monthQuart = DateTime.ParseExact(dateQuarterly, "MMMyy", CultureInfo.InvariantCulture).Month.ToString();
                    string yearQuart  = DateTime.ParseExact(dateQuarterly, "MMMyy", CultureInfo.InvariantCulture).Year.ToString();
                    quarters[i] = monthQuart + "/" + yearQuart;
                }
                finQuartGurufocusModel.Quarterly = quarters;

                // берем первый период, чтобы знать с какого года вести отсчет (всего можем предоставить данные за 4 года)
                string startDate = tdFiscalperiods.ToList()[1].GetAttributeValue("title", "");
                finYearGurufocusModel.startYear = DateTime.ParseExact(startDate, "MMMyy", CultureInfo.InvariantCulture).Year;
            }

            bool noMarketSec = false;

            foreach (var param in financialData)
            {
                var tds = page.Html.CssSelect("td");
                var td  = tds.FirstOrDefault(x => x.Attributes["title"]?.Value == param);
                if (td != null)
                {
                    var tr = td.ParentNode;
                    var financialValues = tr.CssSelect("td").Where(x => x.Attributes["title"]?.Value != null);
                    List <HtmlAgilityPack.HtmlNode> listValues = financialValues.ToList();

                    double[]     dYearValues  = new double[4];
                    double[]     dQuartValues = new double[5];
                    NumberStyles style        = NumberStyles.Number | NumberStyles.AllowCurrencySymbol;
                    CultureInfo  culture      = CultureInfo.CreateSpecificCulture("en-GB");
                    for (int i = 0; i < dYearValues.Length; i++)
                    {
                        Double.TryParse(listValues[i + 1].Attributes["title"].Value, style, culture, out dYearValues[i]);
                    }

                    for (int i = 0; i < dQuartValues.Length; i++)
                    {
                        Double.TryParse(listValues[i + 5].Attributes["title"].Value, style, culture, out dQuartValues[i]);
                    }

                    dYearValues  = dYearValues.Select(d => Math.Round(d, 1)).ToArray();
                    dQuartValues = dQuartValues.Select(d => Math.Round(d, 1)).ToArray();

                    switch (param)
                    {
                    case "Revenue":
                        finYearGurufocusModel.RevenueData  = dYearValues;
                        finQuartGurufocusModel.RevenueData = dQuartValues;
                        break;

                    case "Net Income":
                        finYearGurufocusModel.IncomeData  = dYearValues;
                        finQuartGurufocusModel.IncomeData = dQuartValues;
                        break;

                    case "Cash, Cash Equivalents, Marketable Securities":
                        finYearGurufocusModel.CashData  = dYearValues;
                        finQuartGurufocusModel.CashData = dQuartValues;
                        break;

                    case "Cash and cash equivalents":
                        if (finYearGurufocusModel.CashData == null)
                        {
                            finYearGurufocusModel.CashData  = dYearValues;
                            finQuartGurufocusModel.CashData = dQuartValues;
                            noMarketSec = true;
                        }
                        break;

                    case "Short-term investments":
                        if (noMarketSec)
                        {
                            for (int i = 0; i < finYearGurufocusModel.CashData?.Length; i++)
                            {
                                finYearGurufocusModel.CashData[i]  += dYearValues[i];
                                finQuartGurufocusModel.CashData[i] += dQuartValues[i];
                            }
                            finQuartGurufocusModel.CashData[4] += dQuartValues[4];
                        }
                        break;

                    case "Long-Term Debt & Capital Lease Obligation":
                        finYearGurufocusModel.DebtData  = dYearValues;
                        finQuartGurufocusModel.DebtData = dQuartValues;
                        break;

                    case "Short-Term Debt & Capital Lease Obligation":
                        for (int i = 0; i < finYearGurufocusModel.DebtData?.Length; i++)
                        {
                            finYearGurufocusModel.DebtData[i]  += dYearValues[i];
                            finQuartGurufocusModel.DebtData[i] += dQuartValues[i];
                        }
                        finQuartGurufocusModel.DebtData[4] += dQuartValues[4];
                        break;
                    }
                }
            }
            string result;
            JsonSerializerOptions jsonOptions = new JsonSerializerOptions
            {
                WriteIndented = true,
                Encoder       = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };

            result = JsonSerializer.Serialize <FinYearGurufocusModel>(finYearGurufocusModel, jsonOptions);
            result = "{\"yearData\":" + JsonSerializer.Serialize <FinYearGurufocusModel>(finYearGurufocusModel, jsonOptions) +
                     "," + "\"quarterlyData\":" + JsonSerializer.Serialize <FinQuartGurufocusModel>(finQuartGurufocusModel, jsonOptions) + "}";
            JsonDocument doc = JsonDocument.Parse(result);

            return(Ok(doc.RootElement));
        }