Esempio n. 1
0
        public static string GetFinDataCapitalFileName(this ScrappedCompany c, DocLinkInfo link)
        {
            string date = link.Data.ToString("yyyyMMdd");
            string file = $"{c.CodigoCVM}.{link.DocType}.{date}.CapitalConsolidado.json";
            string path = Path.Combine($"{Program.FINDATA_DIR}", c.CodigoCVM.ToString());

            return(Path.Combine(path, file));
        }
Esempio n. 2
0
        public static string GetFinDataFileName(this ScrappedCompany c, DocLinkInfo link, FinInfoCategoria categoria, FinInfoTipo tipo)
        {
            string date = link.Data.ToString("yyyyMMdd");
            string file = $"{c.CodigoCVM}.{link.DocType}.{date}.{categoria}.{tipo}.json";
            string path = Path.Combine($"{Program.FINDATA_DIR}", c.CodigoCVM.ToString());

            return(Path.Combine(path, file));
        }
Esempio n. 3
0
        static void UpdateCompaniesInDatabase(List <ScrappedCompany> companies)
        {
            if (companies == null)
            {
                companies = ScrappedCompany.LoadCompaniesFromFiles(BASICDATA_DIR);
            }

            EmpresaRepository.InsertOrUpdate(companies);
        }
Esempio n. 4
0
        private static Dictionary <DocInfoType, List <DocLinkInfo> > LoadLinks(ScrappedCompany company)
        {
            var file = company.GetLinksFileName();

            if (!File.Exists(file))
            {
                Console.WriteLine($"arquivo de links da empresa {company.RazaoSocial} não existe");
                log.Error($"arquivo de links da empresa {company.RazaoSocial} não existe");
                return(null);
            }
            string content = File.ReadAllText(file);

            return(JsonConvert.DeserializeObject <Dictionary <DocInfoType, List <DocLinkInfo> > >(content));
        }
Esempio n. 5
0
        private static async Task FillCompanyData(ScrappedCompany c)
        {
            Console.WriteLine($"Obtendo informações básicas de {c.RazaoSocial}");
            log.Info($"Obtendo informações básicas de {c.RazaoSocial}");
            var watch = Stopwatch.StartNew();

            var url      = $"{BASE_URL}/pt-br/mercados/acoes/empresas/ExecutaAcaoConsultaInfoEmp.asp?CodCVM={c.CodigoCVM}&ViewDoc=0";
            var client   = new HttpClient();
            var response = await client.GetStringWithRetryAsync(url);

            ParseBasicData(response, c);
            watch.Stop();
            Console.WriteLine($"dados obtidos em {watch.Elapsed.TotalSeconds} segundos");
        }
Esempio n. 6
0
 private static void FillEmpresaWithCompany(Empresa e, ScrappedCompany c)
 {
     e.Codigo      = c.CodigoCVM;
     e.RazaoSocial = c.RazaoSocial;
     e.NomePregao  = c.NomePregao;
     e.Segmento    = c.Segmento;
     e.CNPJ        = c.CNPJ;
     if (c.AtividadePrincipal != null)
     {
         e.AtividadePrincipal = string.Join(",", c.AtividadePrincipal);
     }
     if (c.ClassificacaoSetorial != null)
     {
         e.ClassificacaoSetorial = string.Join(",", c.ClassificacaoSetorial);
     }
     e.Site = c.Site;
     e.UltimaAtualizacao = c.UltimaAtualizacao;
 }
Esempio n. 7
0
        public static void SaveDocLinks(this ScrappedCompany c, Dictionary <DocInfoType, List <DocLinkInfo> > links)
        {
            log.Info($"Salvando arquivo de links para a empresa {c.RazaoSocial}");

            var filename = c.GetLinksFileName();

            log.Info($"File={filename}");

            string json = JsonConvert.SerializeObject(links, Formatting.Indented);

            var dir = Path.GetDirectoryName(filename);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            File.WriteAllText(filename, json);
        }
Esempio n. 8
0
        private static List <Ticker> GetTickers(ScrappedCompany c)
        {
            log.Info($"Tickers = {string.Join(",", c.CodigosNegociacao)}");

            List <Ticker> tickers = new List <Ticker>();

            foreach (var ticker in c.CodigosNegociacao)
            {
                if (!string.IsNullOrWhiteSpace(ticker))
                {
                    tickers.Add(new Ticker
                    {
                        Nome      = ticker,
                        CodigoCVM = c.CodigoCVM
                    });
                }
            }
            return(tickers);
        }
Esempio n. 9
0
        static async Task ExtractFinancialDataAsync(List <ScrappedCompany> companies)
        {
            if (companies == null)
            {
                companies = ScrappedCompany.LoadCompaniesFromFiles(BASICDATA_DIR);
            }

            IEnumerable <ScrappedCompany> filtered = companies;

            // if (Options.Instance.Company > 0)
            // {
            //     filtered = companies.Where(c => c.CodigoCVM == Options.Instance.Company);
            // }

            foreach (var company in filtered)
            {
                await FinancialDataScrapper.ExtractFinancialInfo(company);
            }
        }
Esempio n. 10
0
        private static List <ScrappedCompany> ParseCompanies(string html)
        {
            log.Info("Extraindo lista de empresas");
            var parser = new HtmlParser();
            var doc    = parser.Parse(html);
            //doc.LoadHtml(html);

            List <ScrappedCompany> companies = new List <ScrappedCompany>();

            var nodes = doc.QuerySelectorAll("tr.GridRow_SiteBmfBovespa, tr.GridAltRow_SiteBmfBovespa");

            foreach (var node in nodes)
            {
                var tds        = node.ChildNodes.Where(n => n.NodeName.ToLowerInvariant() == "td").ToArray();
                var href       = ((IElement)tds[0].FirstChild).Attributes["href"].Value.Trim();
                var razao      = tds[0].TextContent.Trim();
                var nomepregao = tds[1].TextContent.Trim();
                var segmento   = tds[2].TextContent.Trim();

                log.Info($"Extraindo Companhia: {razao}");
                log.Info($"nomepregao = {nomepregao}");
                log.Info($"href = {href}");
                log.Info($"segmento = {segmento}");

                if (segmento != SEGMENTO_MERCADO_BALCAO)
                {
                    var company = new ScrappedCompany();
                    company.RazaoSocial = razao.Trim();
                    company.NomePregao  = nomepregao.Trim();
                    company.Segmento    = SegmentoEnumExtensions.FromString(segmento.Trim());
                    company.CodigoCVM   = GetCodigoCvm(href);
                    companies.Add(company);
                    log.Info($"codigo cvm {company.CodigoCVM}");
                }
                else
                {
                    log.Info($"segmento {SEGMENTO_MERCADO_BALCAO}. Ignorando");
                }
            }

            return(companies);
        }
Esempio n. 11
0
        static async Task ExtractDocLinksAsync(List <ScrappedCompany> companies)
        {
            if (companies == null)
            {
                companies = ScrappedCompany.LoadCompaniesFromFiles(BASICDATA_DIR);
            }

            int counter = 1;

            foreach (var c in companies)
            {
                bool shouldExtract = true;
                // Só deve extrair os links e/ou sobrepor o arquivo da empresa se a data de atualização(company.UltimaAtualizacao) for
                // maior que a data do arquivo (FileTime)
                // ou se o arquivo não existir

                var info = new FileInfo(c.GetLinksFileName());
                if (info.Exists && info.LastWriteTime > c.UltimaAtualizacao)
                {
                    shouldExtract = false;
                }

                if (!shouldExtract)
                {
                    Console.WriteLine($"Empresa {c.RazaoSocial} não necessita extrair links");
                    log.Info($"Empresa {c.RazaoSocial} não necessita extrair links");
                    continue;
                }

                Console.WriteLine($"Extraindo link da empresa {c.RazaoSocial} -- {counter}/{companies.Count}");
                counter += 1;
                log.Info($"Extraindo link da empresa {c.RazaoSocial}");
                var doclinks = await BvmfDocSummaryScrapper.GetDocsInfoReferences(c);

                //save links for company
                c.SaveDocLinks(doclinks);
            }
        }
Esempio n. 12
0
        public static string GetLinksFileName(this ScrappedCompany c)
        {
            string path = $"{Program.LINKS_DIR}{c.CodigoCVM}.json";

            return(path);
        }
        private static async Task <List <DocLinkInfo> > GetDocumentsLinks(DocInfoType docType, ScrappedCompany c)
        {
            log.Info($"Obtendo documentos do tipo {docType} - {c.RazaoSocial}");
            // HistoricoFormularioReferencia.aspx?codigoCVM=6017&tipo=itr&ano=0
            var histUrl = $"HistoricoFormularioReferencia.aspx?codigoCVM={c.CodigoCVM}&tipo={docType.ToString().ToLower()}&ano=0";

            var docs = new List <DocLinkInfo>();

            // name = key
            // kink = value
            Console.WriteLine($"Obtendo lista de documentos {docType}");
            var url      = $"{BvmfScrapper.BASE_URL}{BvmfScrapper.LIST_URL}/{histUrl}";
            var client   = new HttpClient();
            var response = await client.GetStringAsync(url);

            var parser = new HtmlParser();
            var doc    = parser.Parse(response);

            // o segundo h4 que contém o que desejamos. O primeiro é o título da página
            var h4      = doc.QuerySelectorAll("h4").Skip(1).Take(1).Single();
            var list    = GetSectionList(h4);
            var anchors = list.QuerySelectorAll("a");

            foreach (var a in anchors)
            {
                // date, text, link
                //var a = (IHtmlAnchorElement)div.QuerySelector("a");
                docs.Add(new DocLinkInfo(docType, (IHtmlAnchorElement)a));
            }
            return(docs);
        }
Esempio n. 14
0
        public static async Task ExtractFinancialInfo(ScrappedCompany company)
        {
            // load links
            var links = LoadLinks(company);

            if (links == null)
            {
                await Task.FromResult <object>(null);
            }

            // extract ITR
            Console.WriteLine($"Extraindo informações de ITR da empresa {company.RazaoSocial}");
            log.Info($"Extraindo informações de ITR da empresa {company.RazaoSocial}");
            var itrs = links[DocInfoType.ITR];

            itrs = RemoveDuplicates(itrs);

            foreach (var itr in itrs)
            {
                var scrapper = new ItrDfpDataScrapper(company);

                if (!scrapper.DoINeedToExtractAny(itr))
                {
                    continue;
                }

                var docs = await scrapper.GetAvailableDocs(itr);

                if (docs.ComposicaoCapital)
                {
                    await scrapper.ScrapComposicaoCapital(itr);
                }
                if (docs.AtivoIndividual)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Individual, FinInfoCategoria.Ativo);
                }
                if (docs.PassivoIndividual)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Individual, FinInfoCategoria.Passivo);
                }
                if (docs.DREIndividual)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Individual, FinInfoCategoria.DRE);
                }
                if (docs.AtivoConsolidado)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Consolidado, FinInfoCategoria.Ativo);
                }
                if (docs.PassivoConsolidado)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Consolidado, FinInfoCategoria.Passivo);
                }
                if (docs.DREConsolidado)
                {
                    await scrapper.ScrapDoc(itr, FinInfoTipo.Consolidado, FinInfoCategoria.DRE);
                }
            }

            // extract DFP
            Console.WriteLine($"Extraindo informações de DFP da empresa {company.RazaoSocial}");
            log.Info($"Extraindo informações de DFP da empresa {company.RazaoSocial}");
            var dfps = links[DocInfoType.DFP];

            dfps = RemoveDuplicates(dfps);
            foreach (var dfp in dfps)
            {
                var scrapper = new ItrDfpDataScrapper(company);
                await scrapper.ScrapComposicaoCapital(dfp);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Individual, FinInfoCategoria.Ativo);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Individual, FinInfoCategoria.Passivo);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Individual, FinInfoCategoria.DRE);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Consolidado, FinInfoCategoria.Ativo);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Consolidado, FinInfoCategoria.Passivo);

                await scrapper.ScrapDoc(dfp, FinInfoTipo.Consolidado, FinInfoCategoria.DRE);
            }
        }
Esempio n. 15
0
        public static Dictionary <DocInfoType, List <DocLinkInfo> > LoadDocLinksForCompany(this ScrappedCompany company)
        {
            var filename = company.GetLinksFileName();

            log.Info($"Carregando links da empresa {company.RazaoSocial} - {filename}");
            string json = File.ReadAllText(filename);

            return(JsonConvert.DeserializeObject <Dictionary <DocInfoType, List <DocLinkInfo> > >(json));
        }
        public static async Task <Dictionary <DocInfoType, List <DocLinkInfo> > > GetDocsInfoReferences(ScrappedCompany c)
        {
            Console.WriteLine("Obtendo históricos de documentos");
            log.Info($"Obtendo históricos de documentos - {c.RazaoSocial}");

            // link: finacial reports
            // http://bvmf.bmfbovespa.com.br/cias-listadas/empresas-listadas/ResumoDemonstrativosFinanceiros.aspx?codigoCvm=21903&idioma=pt-br
            // __EVENTTARGET = ctl00$contentPlaceHolderConteudo$cmbAno
            // __VIEWSTATE
            // ctl00$contentPlaceHolderConteudo$cmbAno = 2009
            var client = new HttpClient();
            var url    = $"{BvmfScrapper.BASE_URL}{BvmfScrapper.LIST_URL}ResumoDemonstrativosFinanceiros.aspx?codigoCvm={c.CodigoCVM}&idioma=pt-br";

            var response = await client.GetStringWithRetryAsync(url);

            var docLinks = new Dictionary <DocInfoType, List <DocLinkInfo> >();

            // informações trimestrais
            var itrs = await GetDocumentsLinks(DocInfoType.ITR, c);

            docLinks.Add(DocInfoType.ITR, itrs);
            // demonstrações financeiras padronizadas
            var dfps = await GetDocumentsLinks(DocInfoType.DFP, c);

            docLinks.Add(DocInfoType.DFP, dfps);
            // // Formulário de Referência
            // var fres = await GetDocumentsLinks(DocInfoType.FRE, c);
            // docLinks.Add(DocInfoType.FRE, fres);
            // // Formulário Cadastral
            // var fcas = await GetDocumentsLinks(DocInfoType.FCA, c);
            // docLinks.Add(DocInfoType.FCA, fcas);
            // // Informe Trimestral de Securitzadora
            // var secs = await GetDocumentsLinks(DocInfoType.SEC, c);
            // docLinks.Add(DocInfoType.SEC, secs);
            // // Informações Anuais
            // var ians = await GetDocumentsLinks(DocInfoType.IAN, c);
            // docLinks.Add(DocInfoType.IAN, ians);

            return(docLinks);
        }
Esempio n. 17
0
        private static void ParseBasicData(string html, ScrappedCompany c)
        {
            log.Info($"Extraindo informações básicas de {c.RazaoSocial}");
            var parser = new HtmlParser();
            var doc    = parser.Parse(html);
            //doc.LoadHtml(html);


            // first thing: verify if response is "Dados indisponiveis"
            var alert = doc.QuerySelector("div.alert-box");

            if (alert != null)
            {
                if (alert.TextContent.ToLowerInvariant().Contains("dados indisponiveis"))
                {
                    log.Error($"Dados de {c.RazaoSocial} não disponíveis.");
                    throw new UnavailableDataException();
                }
            }


            var rows = doc.QuerySelectorAll("div.row");

            IElement p = null;

            // first row is last update datetime
            p = rows[0].QuerySelector("p.legenda");

            // text = Atualizado em 28/04/2017, às 05h13
            var date = GetDate(p.TextContent.Trim());

            c.UltimaAtualizacao = date;
            log.Info($"Última atualização {c.UltimaAtualizacao.ToString("yyyy-MM-dd HH:mm:ss")}");

            // second row is basic company data
            var tableficha = rows[1].QuerySelector("table.ficha");
            var trs        = tableficha.ChildNodes[1].ChildNodes.Where(n => n.NodeName.ToLowerInvariant() == "tr").OfType <IElement>().ToArray();

            // ignore first TR, we already have this info
            var td = trs[1].QuerySelectorAll("td").Last();

            if (td.TextContent.Contains("Nenhum ativo no Mercado a Vista"))
            {
                log.Info($"A empresa {c.RazaoSocial} não possui ativos no mercado");
            }
            else
            {
                var anchors = td.QuerySelectorAll("a.LinkCodNeg").Select(n => n.TextContent);
                c.CodigosNegociacao = new SortedSet <string>(anchors);
                log.Info($"Códigos de negociação {string.Join(",", c.CodigosNegociacao.ToArray())}");
            }

            var cnpj = trs[2].QuerySelectorAll("td").Last().TextContent.Trim();

            c.CNPJ = cnpj;

            var mainActivity = trs[3].QuerySelectorAll("td").Last().TextContent.Trim();

            if (!string.IsNullOrWhiteSpace(mainActivity))
            {
                c.AtividadePrincipal = (from item in mainActivity.Split('/')
                                        select item.Trim()).ToArray();
            }

            var setorialClassfications = trs[4].QuerySelectorAll("td").Last().TextContent.Trim();

            if (!string.IsNullOrWhiteSpace(setorialClassfications))
            {
                c.ClassificacaoSetorial = (from item in setorialClassfications.Split('/')
                                           select item.Trim()).ToArray();
            }
            if (trs.Length > 5)
            {
                c.Site = trs[5].QuerySelectorAll("td").Last().TextContent.Trim();
            }
        }
Esempio n. 18
0
        public static async Task <List <ScrappedCompany> > GetCompanies()
        {
            Console.WriteLine("Obtendo companhias listadas");
            log.Info("Obtendo companhias listadas");
            var watch = Stopwatch.StartNew();

            var payload = new Dictionary <string, string>
            {
                { "__EVENTTARGET", "ctl00:contentPlaceHolderConteudo:BuscaNomeEmpresa1:btnTodas" }
            };

            string url      = $"{BASE_URL}{LIST_URL}BuscaEmpresaListada.aspx?idioma=pt-br";
            var    client   = new HttpClient();
            var    response = await client.PostDataAsync(url, payload);

            var companies = ParseCompanies(response);

            watch.Stop();
            Console.WriteLine($"{companies.Count} companhias encontradas em {watch.Elapsed.TotalSeconds} segundos");


            foreach (var c in companies)
            {
                try
                {
                    await FillCompanyData(c);
                }catch (UnavailableDataException ex)
                {
                    // ignore this company for now
                    continue;
                }

                string file = c.GetFileName();
                if (File.Exists(file))
                {
                    log.Info($"Arquivo da empresa {c.RazaoSocial} já existe. Verificando data");
                    Console.WriteLine("Empresa já extraída.. verificando....");

                    log.Info($"Carregando empresa do arquivo {file}");
                    var deserialized = ScrappedCompany.Load(file);
                    // deserializer é null quando o arquivo está vazio por algum erro em execuções ateriores
                    if (deserialized != null && c.UltimaAtualizacao <= deserialized.UltimaAtualizacao)
                    {
                        log.Info($"Empresa já está atualizada. Data última atualização: {c.UltimaAtualizacao}");
                        Console.WriteLine("Empresa está atualizada. Pulando");
                        c.NeedsUpdate = false;
                        continue;
                    }
                }

                // save file
                // se a empresa não tiver código de negociação, ignorar
                if (c.CodigosNegociacao?.Count() == 0 || c.CodigosNegociacao == null)
                {
                    Console.WriteLine($"Ignorando empresa {c.RazaoSocial} por não possuir código de negociação");
                    log.Info($"Ignorando empresa {c.RazaoSocial} por não possuir código de negociação");
                }
                else
                {
                    // Só deve sobrepor o arquivo da empresa se a data de atualização (company.UltimaAtualizacao) for
                    // maior que a data do arquivo (FileTime)
                    // ou se o arquivo não existir

                    bool shouldSave = true;
                    var  info       = new FileInfo(c.GetFileName());
                    if (info.Exists && info.LastWriteTime > c.UltimaAtualizacao)
                    {
                        shouldSave = false;
                    }
                    if (shouldSave)
                    {
                        log.Info("Salvando arquivo da empresa");
                        c.Save();
                    }
                    else
                    {
                        Console.WriteLine($"Empresa {c.RazaoSocial} não necessita ser atualizada - arquivo não foi salvo");
                        log.Info($"Empresa {c.RazaoSocial} não necessita ser atualizada - arquivo não foi salvo");
                    }
                }
            }

            // retorna somente as empresas que possuam códigos de negociação
            return(companies.Where(c => c.CodigosNegociacao != null && c.CodigosNegociacao.Count() > 0).ToList());
        }
Esempio n. 19
0
        public static string GetFileName(this ScrappedCompany c)
        {
            string path = $"{Program.BASICDATA_DIR}{c.CodigoCVM}.json";

            return(path);
        }
Esempio n. 20
0
        private static void UpdateExistentsTickers(DataContext db, Empresa empresaInDb, ScrappedCompany company)
        {
            log.Info($"Tickers = {string.Join(",", company.CodigosNegociacao)}");

            // primeiro define todos os ticker como UNCHANGED, assim, os que não forem excluídos os adicionados
            // não serão alterados
            empresaInDb.Tickers.ForEach((ticker) =>
            {
                var entry = db.Entry(ticker);
                if (entry != null)
                {
                    entry.State = EntityState.Unchanged;
                }
            });

            // tickers que existem n banco mas não em company > delete
            empresaInDb.Tickers.RemoveAll(t => !company.CodigosNegociacao.Contains(t.Nome));
            db.RemoveRange(empresaInDb.Tickers.Where(t => !company.CodigosNegociacao.Contains(t.Nome)));

            foreach (var cod in company.CodigosNegociacao)
            {
                // tickers que existem em company mas não no banco > insert
                if (!empresaInDb.Tickers.Any(t => t.Nome == cod) && !string.IsNullOrWhiteSpace(cod))
                {
                    empresaInDb.Tickers.Add(
                        new Ticker()
                    {
                        CodigoCVM = empresaInDb.Codigo,
                        Nome      = cod
                    });
                }
            }
        }
Esempio n. 21
0
 public ItrDfpDataScrapper(ScrappedCompany company)
 {
     this.Company = company;
 }