Skip to content

Classe Fundamentus

Classe responsável por extrair informações do site Fundamentus.

Estas classe contém atributos e métodos capazes de proporcionar uma jornada completa de extração de dados do site Fundamentus que, por sua vez, é especializado em consolidar e disponibilizar informações fundamentalistas de empresas e fundos imobiliários listados na B3.

Para um melhor esclarecimento sobre as reais informações disponibilizadas pelo portal alvo de extração deste módulo Python, consulte o site Fundamentus

Examples:

# Importando classe
from pynvest.scrappers.fundamentus import Fundamentus

# Instanciando objeto da classe
pynvest_scrapper = Fundamentus()

# Extraindo tickers de Ações e FIIs da bolsa
tickers_acoes = pynvest_scrapper.extracao_tickers_de_ativos()
tickers_fiis = pynvest_scrapper.extracao_tickers_de_ativos(tipo="fiis")

# Extraindo indicadores de uma Ação ou FII da bolsa
df_itsa4 = pynvest_scrapper.coleta_indicadores_de_ativo("itsa4")
df_xplg11 = pynvest_scrapper.coleta_indicadores_de_ativo("xplg11")

Parameters:

Name Type Description Default
logger_level int

Nível do objeto de log a ser configurado

INFO
url_tickers_acoes str

URL utilizada para extrair todos os tickers de Ações listadas na B3 através do site Fundamentus. No momento de construção da lib, a URL necessária para tal ação foi mapeada e registrada na variável URL_TICKERS_ACOES acessível no módulo fundamentus.py.

URL_TICKERS_ACOES
url_tickers_acoes str

URL utilizada para extrair todos os tickers de FIIs listados na B3 através do site Fundamentus. No momento de construção da lib, a URL necessária para tal ação foi mapeada e registrada na variável URL_TICKERS_FIIS acessível no módulo fundamentus.py.

URL_TICKERS_ACOES
url_kpis_ticker str

URL utilizada para extrair indicadores fundamentalistas de ativos (Ações e B3) através do site Fundamentus. No momento de construção da lib, a URL necessária para tal ação foi mapeada e registrada na variável URL_KPIS_TICKER acessível no módulo fundamentus.py.

URL_KPIS_TICKER
request_header dict

Dicionário contendo header para configuração das requisições realizadas ao site Fundamentus. No momento de construção da lib, o header da requisição necessário para tal ação foi mapeado e registrao na variável REQUEST_HEADER acessível no módulo fundamentus.py.

REQUEST_HEADER
variation_headings list

Lista de indicadores de variação que precisam ser manualmente definidos por conta da dificuldade de captura automática no processo de Web Scrapping e parse do HTML resultante da requisição. Em linhas gerais, os indicadores fundamentalistas dos ativos contam com tabelas de oscilações que mostram a variação do determinado ativo ao longo do tempo (períodos diários, mensais e até anuais). Tais atributos de variação fogem à regra de extração automática por conta da própria construção do site Fundamentus. Dessa forma, a única forma de extrair e assimilar tais indicadores de variação é associando-os manualmente em um atributo da classe para que os mesmos possam ser considerados no ato da extração. Na visão do usuário da biblioteca, nenhuma ação é requerida, visto que essa "associação manual" é feita diretamente no módulo e não exige nenhum tipo de atualização (a não ser que o próprio site Fundamentus sobre alterações bruscas).

VARIATION_HEADINGS
metadata_cols_acoes dict

Ao extrair indicadores financeiros de Ações da B3, uma série de atributos podem ser analisados e consolidados. Para garantir que as extrações, estas baseadas no parse de uma página HTML, tenham uma padronização pré definida em termos da nomenclatura e da ordem na qual os atributos/indicadores são extraídos, este atributo considera a presença de um dicionário de mapeamento contendo o nome original do atributo/indicador financeiro presente no site e seu respectivo nome já preparado conforme algumas regras e boas práticas de armazenamento de dados, como por exemplo, a remoção de caracteres especiais, espaços, etc. Este processo já é definido previamente no próprio módulo e acessível através da variável METADATA_COLS_ACOES.

METADATA_COLS_ACOES
metadata_cols_fiis dict

Existe uma diferença entre os indicadores oferecidos para Ações e para Fundos Imobiliários. Isto faz total sentido, pois tratam-se de ativos totalmente diferentes. Assim, por conta disso, um dicionário de mapeamento de nomes de colunas para FIIs se faz necessário (nos mesmos moldes do atributo metadata_cols_acoes). Assim como no caso mencionado, este processo já é definido previamente no próprio módulo e acessível através da variável METADATA_COLS_FIIS.

METADATA_COLS_FIIS
Preparação dos atributos da classe Fundamentus

Você deve ter notado que, em essência, todos os atributos da classe são opcionais. Isto foi pensado para aliviar ao máximo o lado do usuário ao consumir a solução, não exigindo que nenhuma configuração adicional seja fornecida (se o usuário assim entender que faça sentido).

Em outras palavras, para começar a utilizar a classe Fundamentus, basta inicializá-la em seu modo padrão e executar seus métodos.

Source code in pynvest/scrappers/fundamentus.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
class Fundamentus:
    """Classe responsável por extrair informações do site Fundamentus.

    Estas classe contém atributos e métodos capazes de proporcionar uma jornada
    completa de extração de dados do site Fundamentus que, por sua vez, é
    especializado em consolidar e disponibilizar informações fundamentalistas
    de empresas e fundos imobiliários listados na B3.

    Para um melhor esclarecimento sobre as reais informações disponibilizadas
    pelo portal alvo de extração deste módulo Python, consulte o site
    [Fundamentus](https://www.fundamentus.com.br/.)

    Examples:
        ```python
        # Importando classe
        from pynvest.scrappers.fundamentus import Fundamentus

        # Instanciando objeto da classe
        pynvest_scrapper = Fundamentus()

        # Extraindo tickers de Ações e FIIs da bolsa
        tickers_acoes = pynvest_scrapper.extracao_tickers_de_ativos()
        tickers_fiis = pynvest_scrapper.extracao_tickers_de_ativos(tipo="fiis")

        # Extraindo indicadores de uma Ação ou FII da bolsa
        df_itsa4 = pynvest_scrapper.coleta_indicadores_de_ativo("itsa4")
        df_xplg11 = pynvest_scrapper.coleta_indicadores_de_ativo("xplg11")
        ```

    Args:
        logger_level (int, optional):
            Nível do objeto de log a ser configurado

        url_tickers_acoes (str, optional):
            URL utilizada para extrair todos os tickers de Ações listadas na
            B3 através do site Fundamentus. No momento de construção da lib,
            a URL necessária para tal ação foi mapeada e registrada na
            variável URL_TICKERS_ACOES acessível no módulo fundamentus.py.

        url_tickers_acoes (str, optional):
            URL utilizada para extrair todos os tickers de FIIs listados na
            B3 através do site Fundamentus. No momento de construção da lib,
            a URL necessária para tal ação foi mapeada e registrada na
            variável URL_TICKERS_FIIS acessível no módulo fundamentus.py.

        url_kpis_ticker (str, optional):
            URL utilizada para extrair indicadores fundamentalistas de ativos
            (Ações e B3) através do site Fundamentus. No momento de construção
            da lib, a URL necessária para tal ação foi mapeada e registrada na
            variável URL_KPIS_TICKER acessível no módulo fundamentus.py.

        request_header (dict, optional):
            Dicionário contendo header para configuração das requisições
            realizadas ao site Fundamentus. No momento de construção
            da lib, o header da requisição necessário para tal ação foi
            mapeado e registrao na variável REQUEST_HEADER acessível no módulo
            fundamentus.py.

        variation_headings (list, optional):
            Lista de indicadores de variação que precisam ser manualmente
            definidos por conta da dificuldade de captura automática no
            processo de Web Scrapping e parse do HTML resultante da requisição.
            Em linhas gerais, os indicadores fundamentalistas dos ativos contam
            com tabelas de oscilações que mostram a variação do determinado
            ativo ao longo do tempo (períodos diários, mensais e até anuais).
            Tais atributos de variação fogem à regra de extração automática
            por conta da própria construção do site Fundamentus. Dessa forma,
            a única forma de extrair e assimilar tais indicadores de variação
            é associando-os manualmente em um atributo da classe para que os
            mesmos possam ser considerados no ato da extração. Na visão do
            usuário da biblioteca, nenhuma ação é requerida, visto que essa
            "associação manual" é feita diretamente no módulo e não exige
            nenhum tipo de atualização (a não ser que o próprio site
            Fundamentus sobre alterações bruscas).

        metadata_cols_acoes (dict, optional):
            Ao extrair indicadores financeiros de Ações da B3, uma série de
            atributos podem ser analisados e consolidados. Para garantir que
            as extrações, estas baseadas no parse de uma página HTML, tenham
            uma padronização pré definida em termos da nomenclatura e da
            ordem na qual os atributos/indicadores são extraídos, este
            atributo considera a presença de um dicionário de mapeamento
            contendo o nome original do atributo/indicador financeiro
            presente no site e seu respectivo nome já preparado conforme
            algumas regras e boas práticas de armazenamento de dados, como
            por exemplo, a remoção de caracteres especiais, espaços, etc.
            Este processo já é definido previamente no próprio módulo e
            acessível através da variável METADATA_COLS_ACOES.

        metadata_cols_fiis (dict, optional):
            Existe uma diferença entre os indicadores oferecidos para Ações
            e para Fundos Imobiliários. Isto faz total sentido, pois tratam-se
            de ativos totalmente diferentes. Assim, por conta disso, um
            dicionário de mapeamento de nomes de colunas para FIIs se faz
            necessário (nos mesmos moldes do atributo metadata_cols_acoes).
            Assim como no caso mencionado, este processo já é definido
            previamente no próprio módulo e acessível através da variável
            METADATA_COLS_FIIS.

    Tip: Preparação dos atributos da classe Fundamentus
        Você deve ter notado que, em essência, todos os atributos da classe
        são opcionais. Isto foi pensado para aliviar ao máximo o lado do
        usuário ao consumir a solução, não exigindo que nenhuma configuração
        adicional seja fornecida (se o usuário assim entender que faça
        sentido).

        Em outras palavras, para começar a utilizar a classe Fundamentus,
        basta inicializá-la em seu modo padrão e executar seus métodos.
    """

    def __init__(
        self,
        logger_level: int = logging.INFO,
        url_tickers_acoes: str = URL_TICKERS_ACOES,
        url_tickers_fiis: str = URL_TICKERS_FIIS,
        url_kpis_ticker: str = URL_KPIS_TICKER,
        request_header: dict = REQUEST_HEADER,
        variation_headings: list = VARIATION_HEADINGS,
        metadata_cols_acoes: dict = METADATA_COLS_ACOES,
        metadata_cols_fiis: dict = METADATA_COLS_FIIS
    ) -> None:
        # Configurando objeto de logger
        self.logger_level = logger_level
        self.logger = log_config(logger_level=self.logger_level)

        # Definindo URLs de requisição ao site
        self.url_tickers_acoes = url_tickers_acoes
        self.url_tickers_fiis = url_tickers_fiis
        self.url_kpis_ticker = url_kpis_ticker

        # Definindo informações das requisições realizadas
        self.request_header = request_header

        # Definindo lista de indicadores financeiros de variação
        self.variation_headings = variation_headings

        # Definindo colunas de indicadores de ativos
        self.metadata_cols_acoes = metadata_cols_acoes
        self.metadata_cols_fiis = metadata_cols_fiis

    @staticmethod
    def _parse_float_cols(df: pd.DataFrame, cols_list: list) -> pd.DataFrame:
        """
        Transforma strings que representam números em objetos do tipo float.

        Este método pode ser utilizado para aplicar conversões de atributos do
        tipo string presentes em um DataFrame do pandas em objetos do tipo
        float (desde que tais strings possam ser convertidas para floats).
        Esta funcionalidade é relevante pois, na extração bruta das informações
        pelo processo de scrapper, todos os atributos são originalmente
        estabelecidos no DataFrame pandas como strings, o que pode dificultar
        análises posteriores por parte de usuários.

        O método conta com alguns tratamentos específicos de strings para
        garantir que as informações numéricas representadas possam ser
        devidamente convertidas. Os tratamentos são:

        1. Substituição de caracteres não numéricos para strings vazias (ex R$)
        2. Substituição de strings vazias por nulos (np.nan)
        3. Substituição de vírgula por ponto
        4. Conversão de string para float

        Args:
            df (pd.DataFrame):
                DataFrame do Pandas contendo as informações extraídas do
                scrapper Fundamentus.

            cols_list (list):
                Lista contendo as colunas decimais (float) a serem tratadas e,
                posteriormente, convertidas.

        Returns:
            Um DataFrame do pandas com os campos do tipo float já convertidos.
        """

        # Iterando sobre colunas numéricas passadas para o método
        for col in cols_list:
            # Substituindo todos os caracteres não numéricos para string vazia
            df[col] = df[col].replace('[^0-9,]', '', regex=True)

            # Substituindo strings vazias por nulos
            df[col] = df[col].replace("", np.nan)

            # Substituindo delimitador de vírgula por ponto
            df[col] = df[col].replace(",", ".", regex=True)

            # Convertendo string para float
            df[col] = df[col].astype(float)

        return df

    @staticmethod
    def _parse_pct_cols(df: pd.DataFrame, cols_list: list) -> pd.DataFrame:
        """
        Transforma strings que representam percentuais em objetos do tipo float

        Este método pode ser utilizado para aplicar conversões de atributos do
        tipo string e que possuem um significado percentual em objetos do tipo
        float (desde que tais strings possam ser convertidas para floats).
        Esta funcionalidade é relevante pois, na extração bruta das informações
        pelo processo de scrapper, todos os atributos são originalmente
        estabelecidos no DataFrame pandas como strings, o que pode dificultar
        análises posteriores por parte de usuários.

        O método conta com alguns tratamentos específicos de strings para
        garantir que as informações numéricas representadas possam ser
        devidamente convertidas. Os tratamentos são:

        1. Substituição do caractere '%' em string vazia
        2. Conversão de string para float
        3. Divisão do valor literal do percentual por 100

        Args:
            df (pd.DataFrame):
                DataFrame do Pandas contendo as informações extraídas do
                scrapper Fundamentus.

            cols_list (list):
                Lista contendo as colunas decimais (float) a serem tratadas e,
                posteriormente, convertidas.

        Returns:
            Um DataFrame do pandas com os campos do tipo float já convertidos.
        """

        # Iterando sobre colunas
        for col in cols_list:
            # Removendo '%' da string
            df[col] = df[col].replace("%", "")

            # Dividindo valor percentual por 100
            df[col] = df[col] / 100

            # Convertendo string para float
            df[col] = df[col].astype(float)

        return df

    def extracao_tickers_de_ativos(self, tipo: str = "ações") -> list[str]:
        """
        Extrai uma lista formada por tickers de ações ou FIIs listados na B3.

        Este método é responsável por extrair uma lista de tickers (siglas) de
        Ações ou Fundos Imobiliários listados na Bolsa brasileira (B3). Para
        isso, os seguintes passos são realizados em tempo de execução:

        1. Faz-se uma requisição à URLs específicas disponibilizada pelo
        site Fundamentus de acordo com tipo definido pelo usuário (tickers
        de Ações ou tickers de FIIs)
        2. O resultado é obtido em formato HTML e tratado através da
        biblioteca BeautifulSoup
        3. Com o conteúdo tratado, extai-se uma lista ordenada de tickers
        de Ações ou de FIIs.

        Note: Sobre os tickers de Ações ou Fundos Imobiliários
            De acordo com a dinâmica do próprio portal Fundamentus, existem
            URLs diferentes para visualização dos tickers de Ações e de FIIs.

            - [Ações](https://www.fundamentus.com.br/resultado.php)
            - [FIIs](https://www.fundamentus.com.br/fii_resultado.php)

            A requisição via requests e o web scrapping via BeautifulSoup é o
            mesmo para ambas as URLs. Entretanto, pelo fato de existirem URLs
            distintas para cada cenário, o usuário precisa informar, em tempo
            de chamada do método, se deseja extrair tickers de Ações ou FIIs.
            Isto pode ser feito pelo parâmetro `tipo` do método.

        Args:
            tipo (str):
                Define que tipo de listagem de tickers da B3 o usuário deseja
                obter. Os valores possíveis são "ações" ou "fiis". Dentro do
                método, existem tratativas em strings para transformar este
                input do usuário em letras minúsculas e sem espaços ao final.

        Returns:
            Uma lista de strings contendo as siglas das Ações ou FIIs.

        Raises:
            Exception: exceção genérica ao tentar realizar a requisição para \
                a URL alvo da extração dos tickers.

        Examples:
            ```python
            # Importando classe
            from pynvest.scrappers.fundamentus import Fundamentus

            # Instanciando objeto da classe
            pynvest_scrapper = Fundamentus()

            # Obtendo tickers de Ações
            tickers_acoes = pynvest_scrapper.extracao_tickers_de_ativos()
            # ['AALR3', 'ABCB3', 'ABCB4', 'ABEV3', 'ABYA3', 'ACES3', ...]

            # Obtendo tickers de Fundos Imobiliários
            tickers_fiis = pynvest_scrapper.extracao_tickers_de_ativos(
                tipo="fiis"
            )
            # ['AAZQ11', 'ABCP11', 'AEFI11', 'AFCR11', 'AFHI11', ...]
            ```
        """

        # Validando se o usuário forneceu o tipo adequado
        tipo_prep = tipo.strip().lower()
        if tipo_prep not in ("ações", "fiis"):
            raise TypeError(f"Tipo inválido para o método (tipo={tipo}). "
                            "Opções válidas: 'ações' ou 'fiis'.")

        # Verificando se o usuário deseja extrair tickers de ações
        if tipo_prep == "ações":
            url = self.url_tickers_acoes
            self.logger.debug("Extraindo lista de tickers de ações da B3")
        else:
            # Usuário deseja extrair tickers de FIIs
            url = self.url_tickers_fiis
            self.logger.debug("Extraindo lista de tickers de FIIs da B3")

        # Coletando conteúdo da requisição em HTML e tratando
        try:
            html_content = requests.get(url, headers=self.request_header).text
            soup = BeautifulSoup(html_content, "lxml")

        except Exception as e:
            self.logger.error(f"Erro de requisição à URL {url}. "
                              f"Exception: {e}")
            raise e

        # Tratando conteúdo e listando tickers
        tickers = [
            row.find_all("a")[0].text.strip()
            for row in soup.find_all("tr")[1:]
        ]
        self.logger.debug("Processo de extração finalizado com sucesso com "
                          f"{len(tickers)} encontrados")

        return sorted(list(set(tickers)))

    def coleta_indicadores_de_ativo(
        self,
        ticker: str,
        parse_dtypes: bool = False
    ) -> pd.DataFrame:
        """
        Extrai indicadores de um ativo específico em um formato de DataFrame.

        Este método é responsável por realizar uma requisição à página
        Funtamentus através de uma URL capaz de entregar indicadores gerais
        sobre um determinado ativo, seja ele um ticker de Ação ou de um FII.
        O resultado é então tratado através de uma série de regras pré
        estabelecidas de acordo com a dinâmica de resposta da requisição e,
        enfim, o retorno ao usuário se dá a partir de um DataFrame do pandas
        pré configurado com os mais variados indicadores do ativo selecionado.

        Em linhas gerais, os passos consolidados no método são:

        1. Faz-se uma requisição à uma URL específica do site Fundamentus para
        expor indicadores fundamentalistas de um determinado ativo (parâmetro
        ticker é substituído como um placeholder na URL antes da requisição).
        2. O resultado é obtido em formato HTML e tratado através da
        biblioteca BeautifulSoup.
        3. Laços de repetição são realizados para iterar sobre todas as
        tabelas do conteúdo HTML obtido em busca da extração dos indicadores.
        4. Um DataFrame pandas é gerado com colunas pré definidas e valores
        extraídos como resultado do tratamento proposto.

        Question: Quais indicadores são extraídos e entregues de fato?
            Considerando o conteúdo presente no site Fundamentus, a URL para
            visualizar indicadores de Ações e FIIs é a mesma, com a diferença
            do ticker substituído como placeholder antes da requisição.

            Entretanto, requisitar indicadores de uma Ação (ex: ITUB3) traz
            resultados diferentes de uma requisição de indicadores de um FII
            (ex: BTLG11). Isto é totalmente plausível, visto que tratam-se de
            ativos completamente diferentes em termos financeiros.

            Dessa forma, para entregar DataFrames adequados para cada tipo de
            ativo, dois mappers distintos foram considerados como variáveis
            estáticas do módulo como dicionários Python contendo todos os
            nomes de colunas/indicadores de Ações e também de FIIs. Tais
            mappers são representados pelas variáveis:

            - METADATA_COLS_ACOES para requisições à indicadores de Ações
            - METADATA_COLS_FIIS para requisições à indicadores de FIIs

            O usuário não precisa informar previamente à execução do método
            se a requisição de indicadores é de uma Ação ou de um FII. Isto é
            feito automaticamente dentro do método através de validações de
            conteúdos das páginas obtidas em cada cenário. Em outras palavras,
            regras internas do próprio método definem quais colunas associar
            ao DataFrame resultante (Ações ou FIIs).

        Args:
            ticker (str):
                Referência do ticker do papel (Ação) ou FII a ser alvo da
                extração de indicadores.

            parse_dtypes (bool):
                Flag booleano para habilitar a execução dos métodos de
                tratamento de tipagem de atributos obtidos no processo de
                extração de indicadores (`__parse_float_cols` e
                `__parse_pct_cols`). Em caso de `parse_dtypes=True`, as
                colunas do tipo `string` que possuem significado numérico
                (ex: "18,5") e de percentual (ex: "5,25%") são convertidas
                para o tipo `float` no DataFrame pandas resultante (18.5 e
                0.0525 nos exemplos fornecidos acima, respectivamente).

        Returns:
            DataFrame pandas com indicadores financeiros do ativo escolhido.

        Raises:
            KeyError: exceção lançada quando há uma tentativa inválida de \
                mapear colunas pré definidas em uma lista ao DataFrame \
                resultante do processo de requisição e tratamento de \
                indicadores financeiros, indicando assim um mismatch entre \
                o conteúdo do site e o conteúdo previamente mapeado e validado

        Examples:
            ```python
            # Importando classe
            from pynvest.scrappers.fundamentus import Fundamentus

            # Instanciando objeto da classe
            pynvest_scrapper = Fundamentus()

            # Obtendo indicadores financeiros de uma Ação
            df_itub3 = pynvest_scrapper.coleta_indicadores_de_ativo("itub3")

            # Ou também, obtendo indicadores financeiros de um FII
            df_btlg11 = pynvest_scrapper.coleta_indicadores_de_ativo("btlg11")
            ```
        """

        # Concatenando URL básica de extração com nome do ativo (ticker)
        url = self.url_kpis_ticker + ticker.strip().upper()

        # Realizando requisição e tratando conteúdo via BeautifulSoup
        html_content = requests.get(url=url, headers=self.request_header).text
        soup = BeautifulSoup(html_content, "lxml")

        # Obtendo todas as tabelas da página de indicadores do ativo
        tables = soup.find_all("table", attrs={'class': 'w728'})

        # Iterando sobre todas as tabelas da página
        financial_data_raw = []
        for table in tables:
            # Extraindo linhas da tabela
            table_row = table.find_all("tr")

            # Iterando sobre linhas da tabela
            for table_data in table_row:
                # Extraindo lista de células da linha
                cells_list = table_data.find_all("td")

                # Coletando headings de células (atributos)
                headings = [
                    cell.text.replace("?", "").strip()
                    for cell in cells_list
                    if "?" in cell.text or cell.text in self.variation_headings
                ]

                # Iterando por headings para procurar por elementos duplicados
                for header in headings:
                    if headings.count(header) > 1:
                        new_header_name = header + "_1"
                        headings[headings.index(header)] = new_header_name

                # Coletando valores das células (indicadores)
                values = [
                    cell.text.strip() for cell in cells_list
                    if ("?" not in cell.text) and (cell.text not in headings)
                ]

                # Gerando dicionário com os elementos das linhas
                table_data_dict = {
                    header: value for header, value in zip(headings, values)
                }

                # Adicionando dicionários que possuem dados válidos extraídos
                if table_data_dict != {}:
                    financial_data_raw.append(table_data_dict)

        # Preparando dicionário único a partir de lista de dicionários extraída
        financial_data = {
            name: value for dictionary in financial_data_raw
            for name, value in dictionary.items()
        }

        # Validando se a extração do ativo é de uma Ação ou de um FII
        if "Papel" in financial_data:
            # Ação: devemos assumir os metadados/indicadores de FIIs
            metadata_cols = self.metadata_cols_acoes
        elif "FII" in financial_data:
            # FII: devemos assumir os metadados/indicadores de Ações
            metadata_cols = self.metadata_cols_fiis
        else:
            raise TypeError("Não foram encontradas informações financeiras "
                            f"para o ticker '{ticker}'. Verifique se o mesmo "
                            "refere-se a uma Ação ou Fundo Imobiliário.")

        # Criando DataFrame pandas com indicadores financeiros do ativo
        df_ativo_raw = pd.DataFrame(financial_data, index=[0])

        # Renomeando atributos/indicadores para melhor análise
        df_indicadores_ativo = df_ativo_raw.rename(
            columns=metadata_cols,
            errors="ignore"
        )

        # Reordenando colunas com base em dicionário de metadados pré definido
        try:
            dataset_cols = list(metadata_cols.values())
            df_indicadores_ativo = df_indicadores_ativo[dataset_cols]

        except KeyError as ke:
            self.logger.debug("Ocorreu um erro ao tentar mapear as colunas "
                              "dos indicadores financeiros no DataFrame "
                              "resultante do processo de web scrapping para "
                              f"o ticker {ticker}.\n\n"
                              "Existem uma série de motivos capazes de "
                              "ocasionar esta falha no mapeamento, como por "
                              "exemplo:\n\n"
                              "1. Alteração no layout do portal Fundamentus.\n"
                              "2. Diferença entre indicadores entre ativos "
                              "distintos.\n\n"
                              "Por experiências de consumo, o layout do site "
                              "não costuma sofrer alterações, sendo mais "
                              "provável a segunda hipótese que defende que "
                              "diferentes ativos podem apresentar diferentes "
                              "indicadores.\n\n"
                              "Pesquise manualmente no site Fundamentus pelos "
                              "ativos 'ITUB3' e 'ITSA4' e veja como os dados "
                              "do balanço patrimonial e do demonstrativo de "
                              "resultados possuem indicadores diferentes.\n\n"
                              f"Exception: {ke}")

            self.logger.debug("Iterando sobre colunas mapeadas e validando "
                              "quais delas não estão presentes no DataFrame "
                              f"resultante para o ticker {ticker}.")
            for col in dataset_cols:
                if col not in list(df_indicadores_ativo.columns):
                    df_indicadores_ativo[col] = None

        # Reordenando DataFrame agora que todas as colunas existem
        df_indicadores_ativo = df_indicadores_ativo[dataset_cols]

        # Adicionando informação de data e hora de processamento
        now = datetime.now(timezone(timedelta(hours=-3)))
        datetime_exec = now.strftime("%d-%m-%Y %H:%M:%S")
        df_indicadores_ativo.loc[:, ["datetime_exec"]] = datetime_exec

        # Validando transformação de tipos primitivos dos atributos
        if parse_dtypes:
            # Coletando atributos de string que representam números
            float_cols_to_parse = [
                col for col in list(df_indicadores_ativo.columns)
                if col[:4] in (
                    "vlr_", "vol_", "num_", "pct_", "qtd_", "max_", "min_",
                    "total_"
                )
            ]

            # Coletando apenas atributos que representam percentuais
            percent_cols_to_parse = [
                col for col in float_cols_to_parse if col[:4] in ("pct_")
            ]

            # Transformando strings que representam números
            df_indicadores_ativo_float_prep = self._parse_float_cols(
                df=df_indicadores_ativo,
                cols_list=float_cols_to_parse
            )

            # Transformando percentuais que representam números
            df_indicadores_ativo_prep = self._parse_pct_cols(
                df=df_indicadores_ativo_float_prep,
                cols_list=percent_cols_to_parse
            )

        else:
            # Em caso de não conversão, manter mesmo DataFrame
            df_indicadores_ativo_prep = df_indicadores_ativo

        return df_indicadores_ativo_prep

extracao_tickers_de_ativos(tipo='ações')

Extrai uma lista formada por tickers de ações ou FIIs listados na B3.

Este método é responsável por extrair uma lista de tickers (siglas) de Ações ou Fundos Imobiliários listados na Bolsa brasileira (B3). Para isso, os seguintes passos são realizados em tempo de execução:

  1. Faz-se uma requisição à URLs específicas disponibilizada pelo site Fundamentus de acordo com tipo definido pelo usuário (tickers de Ações ou tickers de FIIs)
  2. O resultado é obtido em formato HTML e tratado através da biblioteca BeautifulSoup
  3. Com o conteúdo tratado, extai-se uma lista ordenada de tickers de Ações ou de FIIs.
Sobre os tickers de Ações ou Fundos Imobiliários

De acordo com a dinâmica do próprio portal Fundamentus, existem URLs diferentes para visualização dos tickers de Ações e de FIIs.

A requisição via requests e o web scrapping via BeautifulSoup é o mesmo para ambas as URLs. Entretanto, pelo fato de existirem URLs distintas para cada cenário, o usuário precisa informar, em tempo de chamada do método, se deseja extrair tickers de Ações ou FIIs. Isto pode ser feito pelo parâmetro tipo do método.

Parameters:

Name Type Description Default
tipo str

Define que tipo de listagem de tickers da B3 o usuário deseja obter. Os valores possíveis são "ações" ou "fiis". Dentro do método, existem tratativas em strings para transformar este input do usuário em letras minúsculas e sem espaços ao final.

'ações'

Returns:

Type Description
list[str]

Uma lista de strings contendo as siglas das Ações ou FIIs.

Raises:

Type Description
Exception

exceção genérica ao tentar realizar a requisição para a URL alvo da extração dos tickers.

Examples:

# Importando classe
from pynvest.scrappers.fundamentus import Fundamentus

# Instanciando objeto da classe
pynvest_scrapper = Fundamentus()

# Obtendo tickers de Ações
tickers_acoes = pynvest_scrapper.extracao_tickers_de_ativos()
# ['AALR3', 'ABCB3', 'ABCB4', 'ABEV3', 'ABYA3', 'ACES3', ...]

# Obtendo tickers de Fundos Imobiliários
tickers_fiis = pynvest_scrapper.extracao_tickers_de_ativos(
    tipo="fiis"
)
# ['AAZQ11', 'ABCP11', 'AEFI11', 'AFCR11', 'AFHI11', ...]
Source code in pynvest/scrappers/fundamentus.py
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
def extracao_tickers_de_ativos(self, tipo: str = "ações") -> list[str]:
    """
    Extrai uma lista formada por tickers de ações ou FIIs listados na B3.

    Este método é responsável por extrair uma lista de tickers (siglas) de
    Ações ou Fundos Imobiliários listados na Bolsa brasileira (B3). Para
    isso, os seguintes passos são realizados em tempo de execução:

    1. Faz-se uma requisição à URLs específicas disponibilizada pelo
    site Fundamentus de acordo com tipo definido pelo usuário (tickers
    de Ações ou tickers de FIIs)
    2. O resultado é obtido em formato HTML e tratado através da
    biblioteca BeautifulSoup
    3. Com o conteúdo tratado, extai-se uma lista ordenada de tickers
    de Ações ou de FIIs.

    Note: Sobre os tickers de Ações ou Fundos Imobiliários
        De acordo com a dinâmica do próprio portal Fundamentus, existem
        URLs diferentes para visualização dos tickers de Ações e de FIIs.

        - [Ações](https://www.fundamentus.com.br/resultado.php)
        - [FIIs](https://www.fundamentus.com.br/fii_resultado.php)

        A requisição via requests e o web scrapping via BeautifulSoup é o
        mesmo para ambas as URLs. Entretanto, pelo fato de existirem URLs
        distintas para cada cenário, o usuário precisa informar, em tempo
        de chamada do método, se deseja extrair tickers de Ações ou FIIs.
        Isto pode ser feito pelo parâmetro `tipo` do método.

    Args:
        tipo (str):
            Define que tipo de listagem de tickers da B3 o usuário deseja
            obter. Os valores possíveis são "ações" ou "fiis". Dentro do
            método, existem tratativas em strings para transformar este
            input do usuário em letras minúsculas e sem espaços ao final.

    Returns:
        Uma lista de strings contendo as siglas das Ações ou FIIs.

    Raises:
        Exception: exceção genérica ao tentar realizar a requisição para \
            a URL alvo da extração dos tickers.

    Examples:
        ```python
        # Importando classe
        from pynvest.scrappers.fundamentus import Fundamentus

        # Instanciando objeto da classe
        pynvest_scrapper = Fundamentus()

        # Obtendo tickers de Ações
        tickers_acoes = pynvest_scrapper.extracao_tickers_de_ativos()
        # ['AALR3', 'ABCB3', 'ABCB4', 'ABEV3', 'ABYA3', 'ACES3', ...]

        # Obtendo tickers de Fundos Imobiliários
        tickers_fiis = pynvest_scrapper.extracao_tickers_de_ativos(
            tipo="fiis"
        )
        # ['AAZQ11', 'ABCP11', 'AEFI11', 'AFCR11', 'AFHI11', ...]
        ```
    """

    # Validando se o usuário forneceu o tipo adequado
    tipo_prep = tipo.strip().lower()
    if tipo_prep not in ("ações", "fiis"):
        raise TypeError(f"Tipo inválido para o método (tipo={tipo}). "
                        "Opções válidas: 'ações' ou 'fiis'.")

    # Verificando se o usuário deseja extrair tickers de ações
    if tipo_prep == "ações":
        url = self.url_tickers_acoes
        self.logger.debug("Extraindo lista de tickers de ações da B3")
    else:
        # Usuário deseja extrair tickers de FIIs
        url = self.url_tickers_fiis
        self.logger.debug("Extraindo lista de tickers de FIIs da B3")

    # Coletando conteúdo da requisição em HTML e tratando
    try:
        html_content = requests.get(url, headers=self.request_header).text
        soup = BeautifulSoup(html_content, "lxml")

    except Exception as e:
        self.logger.error(f"Erro de requisição à URL {url}. "
                          f"Exception: {e}")
        raise e

    # Tratando conteúdo e listando tickers
    tickers = [
        row.find_all("a")[0].text.strip()
        for row in soup.find_all("tr")[1:]
    ]
    self.logger.debug("Processo de extração finalizado com sucesso com "
                      f"{len(tickers)} encontrados")

    return sorted(list(set(tickers)))

coleta_indicadores_de_ativo(ticker, parse_dtypes=False)

Extrai indicadores de um ativo específico em um formato de DataFrame.

Este método é responsável por realizar uma requisição à página Funtamentus através de uma URL capaz de entregar indicadores gerais sobre um determinado ativo, seja ele um ticker de Ação ou de um FII. O resultado é então tratado através de uma série de regras pré estabelecidas de acordo com a dinâmica de resposta da requisição e, enfim, o retorno ao usuário se dá a partir de um DataFrame do pandas pré configurado com os mais variados indicadores do ativo selecionado.

Em linhas gerais, os passos consolidados no método são:

  1. Faz-se uma requisição à uma URL específica do site Fundamentus para expor indicadores fundamentalistas de um determinado ativo (parâmetro ticker é substituído como um placeholder na URL antes da requisição).
  2. O resultado é obtido em formato HTML e tratado através da biblioteca BeautifulSoup.
  3. Laços de repetição são realizados para iterar sobre todas as tabelas do conteúdo HTML obtido em busca da extração dos indicadores.
  4. Um DataFrame pandas é gerado com colunas pré definidas e valores extraídos como resultado do tratamento proposto.
Quais indicadores são extraídos e entregues de fato?

Considerando o conteúdo presente no site Fundamentus, a URL para visualizar indicadores de Ações e FIIs é a mesma, com a diferença do ticker substituído como placeholder antes da requisição.

Entretanto, requisitar indicadores de uma Ação (ex: ITUB3) traz resultados diferentes de uma requisição de indicadores de um FII (ex: BTLG11). Isto é totalmente plausível, visto que tratam-se de ativos completamente diferentes em termos financeiros.

Dessa forma, para entregar DataFrames adequados para cada tipo de ativo, dois mappers distintos foram considerados como variáveis estáticas do módulo como dicionários Python contendo todos os nomes de colunas/indicadores de Ações e também de FIIs. Tais mappers são representados pelas variáveis:

  • METADATA_COLS_ACOES para requisições à indicadores de Ações
  • METADATA_COLS_FIIS para requisições à indicadores de FIIs

O usuário não precisa informar previamente à execução do método se a requisição de indicadores é de uma Ação ou de um FII. Isto é feito automaticamente dentro do método através de validações de conteúdos das páginas obtidas em cada cenário. Em outras palavras, regras internas do próprio método definem quais colunas associar ao DataFrame resultante (Ações ou FIIs).

Parameters:

Name Type Description Default
ticker str

Referência do ticker do papel (Ação) ou FII a ser alvo da extração de indicadores.

required
parse_dtypes bool

Flag booleano para habilitar a execução dos métodos de tratamento de tipagem de atributos obtidos no processo de extração de indicadores (__parse_float_cols e __parse_pct_cols). Em caso de parse_dtypes=True, as colunas do tipo string que possuem significado numérico (ex: "18,5") e de percentual (ex: "5,25%") são convertidas para o tipo float no DataFrame pandas resultante (18.5 e 0.0525 nos exemplos fornecidos acima, respectivamente).

False

Returns:

Type Description
DataFrame

DataFrame pandas com indicadores financeiros do ativo escolhido.

Raises:

Type Description
KeyError

exceção lançada quando há uma tentativa inválida de mapear colunas pré definidas em uma lista ao DataFrame resultante do processo de requisição e tratamento de indicadores financeiros, indicando assim um mismatch entre o conteúdo do site e o conteúdo previamente mapeado e validado

Examples:

# Importando classe
from pynvest.scrappers.fundamentus import Fundamentus

# Instanciando objeto da classe
pynvest_scrapper = Fundamentus()

# Obtendo indicadores financeiros de uma Ação
df_itub3 = pynvest_scrapper.coleta_indicadores_de_ativo("itub3")

# Ou também, obtendo indicadores financeiros de um FII
df_btlg11 = pynvest_scrapper.coleta_indicadores_de_ativo("btlg11")
Source code in pynvest/scrappers/fundamentus.py
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
def coleta_indicadores_de_ativo(
    self,
    ticker: str,
    parse_dtypes: bool = False
) -> pd.DataFrame:
    """
    Extrai indicadores de um ativo específico em um formato de DataFrame.

    Este método é responsável por realizar uma requisição à página
    Funtamentus através de uma URL capaz de entregar indicadores gerais
    sobre um determinado ativo, seja ele um ticker de Ação ou de um FII.
    O resultado é então tratado através de uma série de regras pré
    estabelecidas de acordo com a dinâmica de resposta da requisição e,
    enfim, o retorno ao usuário se dá a partir de um DataFrame do pandas
    pré configurado com os mais variados indicadores do ativo selecionado.

    Em linhas gerais, os passos consolidados no método são:

    1. Faz-se uma requisição à uma URL específica do site Fundamentus para
    expor indicadores fundamentalistas de um determinado ativo (parâmetro
    ticker é substituído como um placeholder na URL antes da requisição).
    2. O resultado é obtido em formato HTML e tratado através da
    biblioteca BeautifulSoup.
    3. Laços de repetição são realizados para iterar sobre todas as
    tabelas do conteúdo HTML obtido em busca da extração dos indicadores.
    4. Um DataFrame pandas é gerado com colunas pré definidas e valores
    extraídos como resultado do tratamento proposto.

    Question: Quais indicadores são extraídos e entregues de fato?
        Considerando o conteúdo presente no site Fundamentus, a URL para
        visualizar indicadores de Ações e FIIs é a mesma, com a diferença
        do ticker substituído como placeholder antes da requisição.

        Entretanto, requisitar indicadores de uma Ação (ex: ITUB3) traz
        resultados diferentes de uma requisição de indicadores de um FII
        (ex: BTLG11). Isto é totalmente plausível, visto que tratam-se de
        ativos completamente diferentes em termos financeiros.

        Dessa forma, para entregar DataFrames adequados para cada tipo de
        ativo, dois mappers distintos foram considerados como variáveis
        estáticas do módulo como dicionários Python contendo todos os
        nomes de colunas/indicadores de Ações e também de FIIs. Tais
        mappers são representados pelas variáveis:

        - METADATA_COLS_ACOES para requisições à indicadores de Ações
        - METADATA_COLS_FIIS para requisições à indicadores de FIIs

        O usuário não precisa informar previamente à execução do método
        se a requisição de indicadores é de uma Ação ou de um FII. Isto é
        feito automaticamente dentro do método através de validações de
        conteúdos das páginas obtidas em cada cenário. Em outras palavras,
        regras internas do próprio método definem quais colunas associar
        ao DataFrame resultante (Ações ou FIIs).

    Args:
        ticker (str):
            Referência do ticker do papel (Ação) ou FII a ser alvo da
            extração de indicadores.

        parse_dtypes (bool):
            Flag booleano para habilitar a execução dos métodos de
            tratamento de tipagem de atributos obtidos no processo de
            extração de indicadores (`__parse_float_cols` e
            `__parse_pct_cols`). Em caso de `parse_dtypes=True`, as
            colunas do tipo `string` que possuem significado numérico
            (ex: "18,5") e de percentual (ex: "5,25%") são convertidas
            para o tipo `float` no DataFrame pandas resultante (18.5 e
            0.0525 nos exemplos fornecidos acima, respectivamente).

    Returns:
        DataFrame pandas com indicadores financeiros do ativo escolhido.

    Raises:
        KeyError: exceção lançada quando há uma tentativa inválida de \
            mapear colunas pré definidas em uma lista ao DataFrame \
            resultante do processo de requisição e tratamento de \
            indicadores financeiros, indicando assim um mismatch entre \
            o conteúdo do site e o conteúdo previamente mapeado e validado

    Examples:
        ```python
        # Importando classe
        from pynvest.scrappers.fundamentus import Fundamentus

        # Instanciando objeto da classe
        pynvest_scrapper = Fundamentus()

        # Obtendo indicadores financeiros de uma Ação
        df_itub3 = pynvest_scrapper.coleta_indicadores_de_ativo("itub3")

        # Ou também, obtendo indicadores financeiros de um FII
        df_btlg11 = pynvest_scrapper.coleta_indicadores_de_ativo("btlg11")
        ```
    """

    # Concatenando URL básica de extração com nome do ativo (ticker)
    url = self.url_kpis_ticker + ticker.strip().upper()

    # Realizando requisição e tratando conteúdo via BeautifulSoup
    html_content = requests.get(url=url, headers=self.request_header).text
    soup = BeautifulSoup(html_content, "lxml")

    # Obtendo todas as tabelas da página de indicadores do ativo
    tables = soup.find_all("table", attrs={'class': 'w728'})

    # Iterando sobre todas as tabelas da página
    financial_data_raw = []
    for table in tables:
        # Extraindo linhas da tabela
        table_row = table.find_all("tr")

        # Iterando sobre linhas da tabela
        for table_data in table_row:
            # Extraindo lista de células da linha
            cells_list = table_data.find_all("td")

            # Coletando headings de células (atributos)
            headings = [
                cell.text.replace("?", "").strip()
                for cell in cells_list
                if "?" in cell.text or cell.text in self.variation_headings
            ]

            # Iterando por headings para procurar por elementos duplicados
            for header in headings:
                if headings.count(header) > 1:
                    new_header_name = header + "_1"
                    headings[headings.index(header)] = new_header_name

            # Coletando valores das células (indicadores)
            values = [
                cell.text.strip() for cell in cells_list
                if ("?" not in cell.text) and (cell.text not in headings)
            ]

            # Gerando dicionário com os elementos das linhas
            table_data_dict = {
                header: value for header, value in zip(headings, values)
            }

            # Adicionando dicionários que possuem dados válidos extraídos
            if table_data_dict != {}:
                financial_data_raw.append(table_data_dict)

    # Preparando dicionário único a partir de lista de dicionários extraída
    financial_data = {
        name: value for dictionary in financial_data_raw
        for name, value in dictionary.items()
    }

    # Validando se a extração do ativo é de uma Ação ou de um FII
    if "Papel" in financial_data:
        # Ação: devemos assumir os metadados/indicadores de FIIs
        metadata_cols = self.metadata_cols_acoes
    elif "FII" in financial_data:
        # FII: devemos assumir os metadados/indicadores de Ações
        metadata_cols = self.metadata_cols_fiis
    else:
        raise TypeError("Não foram encontradas informações financeiras "
                        f"para o ticker '{ticker}'. Verifique se o mesmo "
                        "refere-se a uma Ação ou Fundo Imobiliário.")

    # Criando DataFrame pandas com indicadores financeiros do ativo
    df_ativo_raw = pd.DataFrame(financial_data, index=[0])

    # Renomeando atributos/indicadores para melhor análise
    df_indicadores_ativo = df_ativo_raw.rename(
        columns=metadata_cols,
        errors="ignore"
    )

    # Reordenando colunas com base em dicionário de metadados pré definido
    try:
        dataset_cols = list(metadata_cols.values())
        df_indicadores_ativo = df_indicadores_ativo[dataset_cols]

    except KeyError as ke:
        self.logger.debug("Ocorreu um erro ao tentar mapear as colunas "
                          "dos indicadores financeiros no DataFrame "
                          "resultante do processo de web scrapping para "
                          f"o ticker {ticker}.\n\n"
                          "Existem uma série de motivos capazes de "
                          "ocasionar esta falha no mapeamento, como por "
                          "exemplo:\n\n"
                          "1. Alteração no layout do portal Fundamentus.\n"
                          "2. Diferença entre indicadores entre ativos "
                          "distintos.\n\n"
                          "Por experiências de consumo, o layout do site "
                          "não costuma sofrer alterações, sendo mais "
                          "provável a segunda hipótese que defende que "
                          "diferentes ativos podem apresentar diferentes "
                          "indicadores.\n\n"
                          "Pesquise manualmente no site Fundamentus pelos "
                          "ativos 'ITUB3' e 'ITSA4' e veja como os dados "
                          "do balanço patrimonial e do demonstrativo de "
                          "resultados possuem indicadores diferentes.\n\n"
                          f"Exception: {ke}")

        self.logger.debug("Iterando sobre colunas mapeadas e validando "
                          "quais delas não estão presentes no DataFrame "
                          f"resultante para o ticker {ticker}.")
        for col in dataset_cols:
            if col not in list(df_indicadores_ativo.columns):
                df_indicadores_ativo[col] = None

    # Reordenando DataFrame agora que todas as colunas existem
    df_indicadores_ativo = df_indicadores_ativo[dataset_cols]

    # Adicionando informação de data e hora de processamento
    now = datetime.now(timezone(timedelta(hours=-3)))
    datetime_exec = now.strftime("%d-%m-%Y %H:%M:%S")
    df_indicadores_ativo.loc[:, ["datetime_exec"]] = datetime_exec

    # Validando transformação de tipos primitivos dos atributos
    if parse_dtypes:
        # Coletando atributos de string que representam números
        float_cols_to_parse = [
            col for col in list(df_indicadores_ativo.columns)
            if col[:4] in (
                "vlr_", "vol_", "num_", "pct_", "qtd_", "max_", "min_",
                "total_"
            )
        ]

        # Coletando apenas atributos que representam percentuais
        percent_cols_to_parse = [
            col for col in float_cols_to_parse if col[:4] in ("pct_")
        ]

        # Transformando strings que representam números
        df_indicadores_ativo_float_prep = self._parse_float_cols(
            df=df_indicadores_ativo,
            cols_list=float_cols_to_parse
        )

        # Transformando percentuais que representam números
        df_indicadores_ativo_prep = self._parse_pct_cols(
            df=df_indicadores_ativo_float_prep,
            cols_list=percent_cols_to_parse
        )

    else:
        # Em caso de não conversão, manter mesmo DataFrame
        df_indicadores_ativo_prep = df_indicadores_ativo

    return df_indicadores_ativo_prep