Criando base de dados com as atas do Copom

Nesse post vamos apresentar um script simples para obter os textos de todas as atas do Comitê de Política Monetária (Copom) e criar uma base pronta para exploração e análise textual

Saulo Guerra
05-31-2020

O Comitê de Política Monetária (Copom) se reúne a cada 45 dias para definir taxa básica de juros da economia (Selic). Além da definição da taxa Selic, essas reuniões produzem textos analíticos justificando, contextualizando e detalhando todo o embasamento técnico da decisão tomada pelo comitê. Esses textos são as Atas do Copom e podem ser encontradas em https://www.bcb.gov.br/publicacoes/atascopom.

As Atas são cuidadosamente avaliadas pelos agentes de mercado no intuito de ajustarem suas expectativas frente ao entendimento do cenário macroeconômico que o Copom apresenta. Trata-se de um conjunto de textos muito importante, escritos com cuidado para tentar passar sinais claros e convincentes aos agentes econômicos.

Neste post vamos montar uma base de dados com toda história de textos das Atas do Copom. Após trazer esses textos para o R, iremos futuramente (em outro post) experimentar explorações e análise textual com essas Atas.

O script resumido (e um pouco desorganizado) está disponível em https://github.com/sauloguerra/r-atascopom

Fonte dos dados

Explorando um pouco a página de divulgação das atas do Copom, mais precisamente na página https://www.bcb.gov.br/publicacoes/atascopom/cronologicos, é possível notar chamada a dois endpoints de API, um para atas mais novas e outro para atas antigas. Clique nos links abaixo para ver o json em seu browser.

Conteúdo da cahamda antiga: https://www.bcb.gov.br/api/servico/sitebcb/atascopom-conteudo/ultimas?quantidade=1000&filtro=

Conteúdo da chamada nova: https://www.bcb.gov.br/api/servico/sitebcb/atascopom/ultimas?quantidade=1000&filtro=

A API que retorna as atas mais recentes informa o link direto de acesso ao pdf da ata no campo “Url”. Já a API das atas mais antigas retorna um link com a ata em html no campo “LinkPagina”. Precisaremos definir uma abordagem diferente para cada tipo.

Basicamente os dois endpoints retornam 3 campos de interesse que iremos utilizar: DataReferencia, Titulo e Link. Dessa forma, a estratégia inicial é montar um dataframe com o link de todas as atas, antigas e novas. Em seguida, percorremos esse links baixando o conteúdo (texto) de cada ata.

Começamos carregando alguns pacotes:


## chamadas e scraping
library(jsonlite)
library(RCurl)
library(rvest)
## extração e manipulação
library(tidyverse)
library(pdftools)
library(glue)

Definimos os caminhos das chamadas conforme os links mostrados acima:


## url base para todas as chamadas
url <- "https://www.bcb.gov.br"
api_antigas <- "/api/servico/sitebcb/atascopom-conteudo/ultimas?quantidade=1000&filtro="
api_novas <- "/api/servico/sitebcb/atascopom/ultimas?quantidade=1000&filtro="

Vamos a construção de um dataframe com o link de todas as atas. Chamamos as consultas e extraímos do conteúdo os campos de data, título e o link, indicando o tipo de cada ata. Lembrando, html são as atas antigas, pdf as novas.


json_links_antigos <- getURL(glue("{url}{api_antigas}"))

df_atas_antigas <- fromJSON(json_links_antigos, flatten = TRUE) %>%
  .$conteudo %>%
  select(DataReferencia, Titulo, LinkPagina) %>%
  mutate(Tipo = "html")

str(df_atas_antigas)

'data.frame':   179 obs. of  4 variables:
 $ DataReferencia: chr  "2016-06-08T03:00:00Z" "2016-04-27T03:00:00Z" "2016-03-02T03:00:00Z" "2016-01-20T02:00:00Z" ...
 $ Titulo        : chr  "199ª Reunião" "198ª Reunião" "197ª Reunião" "196ª Reunião" ...
 $ LinkPagina    : chr  "/publicacoes/atascopom/08062016" "/publicacoes/atascopom/27042016" "/publicacoes/atascopom/02032016" "/publicacoes/atascopom/20012016" ...
 $ Tipo          : chr  "html" "html" "html" "html" ...

json_links_novos <- getURL(glue("{url}{api_novas}"))

df_atas_novas <- fromJSON(json_links_novos, flatten = TRUE) %>%
  .$conteudo %>%
  select(DataReferencia, Titulo, LinkPagina = Url) %>%
  mutate(Tipo = "pdf")

str(df_atas_novas)

'data.frame':   31 obs. of  4 variables:
 $ DataReferencia: chr  "2020-05-06T03:00:00Z" "2020-03-18T03:00:00Z" "2020-02-05T03:00:00Z" "2019-12-11T03:00:00Z" ...
 $ Titulo        : chr  "230ª Reunião" "229ª Reunião" "228ª Reunião" "227ª Reunião" ...
 $ LinkPagina    : chr  "/content/copom/atascopom/Copom230-not20200506230.pdf" "/content/copom/atascopom/Copom229-not20200318229.pdf" "/content/copom/atascopom/Copom228-not20200205228.pdf" "/content/copom/atascopom/Copom227-not20191211227.pdf" ...
 $ Tipo          : chr  "pdf" "pdf" "pdf" "pdf" ...

Repare que por conta da diferença de retorno das duas chamadas, renomeamos o campo Url para LinkPagina, compatibilizando os dois grupos em um dataframe só.


df_atas <- bind_rows(df_atas_novas, df_atas_antigas)

str(df_atas)

'data.frame':   210 obs. of  4 variables:
 $ DataReferencia: chr  "2020-05-06T03:00:00Z" "2020-03-18T03:00:00Z" "2020-02-05T03:00:00Z" "2019-12-11T03:00:00Z" ...
 $ Titulo        : chr  "230ª Reunião" "229ª Reunião" "228ª Reunião" "227ª Reunião" ...
 $ LinkPagina    : chr  "/content/copom/atascopom/Copom230-not20200506230.pdf" "/content/copom/atascopom/Copom229-not20200318229.pdf" "/content/copom/atascopom/Copom228-not20200205228.pdf" "/content/copom/atascopom/Copom227-not20191211227.pdf" ...
 $ Tipo          : chr  "pdf" "pdf" "pdf" "pdf" ...

head(df_atas)

        DataReferencia       Titulo
1 2020-05-06T03:00:00Z 230ª Reunião
2 2020-03-18T03:00:00Z 229ª Reunião
3 2020-02-05T03:00:00Z 228ª Reunião
4 2019-12-11T03:00:00Z 227ª Reunião
5 2019-10-30T03:00:00Z 226ª Reunião
6 2019-09-18T03:00:00Z 225ª Reunião
                                            LinkPagina Tipo
1 /content/copom/atascopom/Copom230-not20200506230.pdf  pdf
2 /content/copom/atascopom/Copom229-not20200318229.pdf  pdf
3 /content/copom/atascopom/Copom228-not20200205228.pdf  pdf
4 /content/copom/atascopom/Copom227-not20191211227.pdf  pdf
5 /content/copom/atascopom/Copom226-not20191030226.pdf  pdf
6 /content/copom/atascopom/Copom225-not20190918225.pdf  pdf

tail(df_atas)

          DataReferencia      Titulo                      LinkPagina
205 1998-07-01T03:00:00Z 26ª Reunião /publicacoes/atascopom/01071998
206 1998-06-01T03:00:00Z 25ª Reunião /publicacoes/atascopom/01061998
207 1998-05-01T03:00:00Z 24ª Reunião /publicacoes/atascopom/01051998
208 1998-04-01T03:00:00Z 23ª Reunião /publicacoes/atascopom/01041998
209 1998-03-01T03:00:00Z 22ª Reunião /publicacoes/atascopom/01031998
210 1998-01-28T02:00:00Z 21ª Reunião /publicacoes/atascopom/28011998
    Tipo
205 html
206 html
207 html
208 html
209 html
210 html

Teremos as atas desde janeiro de 1998 até a última publicada, totalizando mais de 200 atas.


df_atas %>% filter(DataReferencia == min(DataReferencia))

        DataReferencia      Titulo                      LinkPagina
1 1998-01-28T02:00:00Z 21ª Reunião /publicacoes/atascopom/28011998
  Tipo
1 html

df_atas %>% filter(DataReferencia == max(DataReferencia))

        DataReferencia       Titulo
1 2020-05-06T03:00:00Z 230ª Reunião
                                            LinkPagina Tipo
1 /content/copom/atascopom/Copom230-not20200506230.pdf  pdf

nrow(df_atas)

[1] 210

Obtendo os textos das Atas

Após consolidarmos um dataframe com a data da ata, o título da reunião e o link onde podemos obter a íntegra dos textos. Vamos percorrer esse dataframe acessando cada link e trazendo o texto para uma coluna nova no dataframe.

O desafio nesse momento é justamente lidar com duas fontes diferentes: as atas mais novas estão em pdf, as mais antigas estão em html. Nesse caso, vamos definir duas funções diferentes para obter o texto, uma para html e outra para pdf.

O link direto ao conteúdo das atas novas já está explícito em nosso dataframe, então basta acessar diretamente e converter de pdf para texto com o pacote pdftools


conteudo_pdf <- function(link, url = "https://www.bcb.gov.br") {
  pdf <- pdf_text(glue("{url}{link}")) %>%
    as_vector() %>%
    glue_collapse()

  return(pdf)
}

As atas antigas são um pouco mais desafiadoras de serem obtidas, mas nada que uma rápida investigação na página não resolva. A página tem uma renderização interna que recebe o html formatado de uma chamada própria no seguinte formato (clique para ver o json no seu browser):

https://www.bcb.gov.br/api/servico/sitebcb/atascopom-conteudo/principal?filtro=IdentificadorUrl%20eq%20%2708062016%27

Retirando os encodes de URL para ficar mais fácil de entender, basicamente a chamada se baseia no seguinte parâmetro:

filtro = IdentificadorUrl eq ‘08062016’

Sendo assim, basta extrair o código numérico do link em nosso dataframe e encaixá-lo nessa chamada (com encode URL adequado). Essa nova chamada nos dará acesso a um json que retorna o html pronto para ser renderizado em tela. Ele fica disponível no parâmetro “conteudo > OutrasInformacoes” do json retorno.


conteudo_html <- function(link, url = "https://www.bcb.gov.br") {
  api <- "/api/servico/sitebcb/atascopom-conteudo/principal?filtro=IdentificadorUrl"
  codigo <- str_extract_all(link, "\\d+")
  codigo <- URLencode(glue(" eq '{codigo}'"), reserved = T)
  
  json <- glue("{url}{api}{codigo}") %>%
    fromJSON()
  
  txt <- read_html(json$conteudo$OutrasInformacoes) %>%
    html_text() %>%
    str_squish()
  
  return(txt)
}

Com essas duas funções, basta percorrer nosso dataframe com os links de referência e guardar o texto das atas em uma nova coluna. Para exercício deste post, vamos baixar uma amostra aleatória de apenas 20 atas. Mas bastaria tirar essa restrição para baixar todas.

Ao final, teremos uma colina extra chamada íntegra contendo o texto da ata, além das demais colunas com data e numeração da reunião.


final <- df_atas %>%
  sample_n(20) %>% 
  mutate(
    integra = map2_chr(Tipo, LinkPagina, ~ {
      if (.x == "pdf") {
        return(conteudo_pdf(.y))
      }

      return(conteudo_html(.y))
    })
  )

str(final)

'data.frame':   20 obs. of  5 variables:
 $ DataReferencia: chr  "1999-04-01T03:00:00Z" "2018-12-12T02:00:00Z" "2013-11-27T02:00:00Z" "2005-04-28T03:00:00Z" ...
 $ Titulo        : chr  "34ª Reunião" "219ª Reunião" "179ª Reunião" "107ª Reunião" ...
 $ LinkPagina    : chr  "/publicacoes/atascopom/01041999" "/content/copom/atascopom/COPOM219-not20181212219.pdf" "/publicacoes/atascopom/27112013" "/publicacoes/atascopom/28042005" ...
 $ Tipo          : chr  "html" "pdf" "html" "html" ...
 $ integra       : chr  "Sumário Preços e Nível de Atividade Agregados Monetários e Crédito Finanças Públicas Balanço de Pagamentos Ambi"| __truncated__ "Ata da 219ª Reunião do\nComitê de Política Monetária (Copom) do\nBanco Central do Brasil\n11 e 12 de dezembro d"| __truncated__ "Sumário Evolução recente da economia Avaliação prospectiva das tendências da inflação Implementação da política"| __truncated__ "Sumário Evolução recente da inflação Avaliação prospectiva das tendências da inflação Implementação da política"| __truncated__ ...

Vamos dar uma rápida olhada nos textos, mas suprimindo algumas partes para não poluir muito a postagem:


parcial <- function(texto) {
  paste(
    str_sub(texto, end = 500),
    "(.......)",
    str_sub(texto, -500)
  )
}

final %>%
  slice(1) %>%
  mutate(integra = parcial(integra))

        DataReferencia      Titulo                      LinkPagina
1 1999-04-01T03:00:00Z 34ª Reunião /publicacoes/atascopom/01041999
  Tipo
1 html
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              integra
1 Sumário Preços e Nível de Atividade Agregados Monetários e Crédito Finanças Públicas Balanço de Pagamentos Ambiente Externo Evolução do Mercado de Câmbio Doméstico e Posição das Reservas Internacionais Liquidez Bancária Mercado Monetário e Operações de Mercado Aberto Diretrizes de Política Monetária Nota explicativa da decisão do COPOM de 14/04/1999 Data: 14.04.1999 Local: Sala de reuniões do 8º andar do Edifício-Sede do Banco Central - Brasília-DF Horário de início:16:55 h Horário de término:19 (.......) nto de exercer forte pressão deflacionária. Segundo, no âmbito externo havia o fator negativo representado pela guerra dos Bálcãs, cuja duração já ultrapassava o previsto. Decidiu-se, assim, por redução ainda cautelosa da meta de taxa SELIC, para 34% ao ano, mantendo-se o viés de redução. O COPOM entende que o mecanismo do viés deve ser utilizado com parcimônia, mas argumentou-se que as incertezas ainda existentes na economia brasileira conduzem necessariamente à opção por um viés ainda elevado.

final %>%
  slice(5) %>%
  mutate(integra = parcial(integra))

        DataReferencia       Titulo                      LinkPagina
1 2012-03-07T03:00:00Z 165ª Reunião /publicacoes/atascopom/07032012
  Tipo
1 html
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              integra
1 Sumário Evolução recente da economia Avaliação prospectiva das tendências da inflação Implementação da política monetária Inflação Atividade econômica Expectativas e sondagens Mercado de trabalho Crédito e inadimplência Ambiente externo Comércio exterior e reservas internacionais Mercado monetário e operações de mercado aberto Data: 6 e 7/3/2012 Local: Sala de reuniões do 8º andar (6/3) e do 20º andar (7/3) do Edifício-Sede do Banco Central do Brasil – Brasília – DF Horário de início: 16h20 (6/3 (.......)  bilhões, sendo R$26,7 bilhões em Letras do Tesouro Nacional (LTN) com vencimento em 2012, 2013, 2014 e 2016, e R$2,8 bilhões em Notas do Tesouro Nacional – Série F (NTN-F) com vencimento em 2018 e 2021. As vendas de Letras Financeiras do Tesouro (LFT) totalizaram R$2,6 bilhões, com emissão de títulos com vencimento em 2018. Nos leilões de Notas do Tesouro Nacional – Série B (NTN-B), foram vendidos títulos com vencimento em 2016, 2018, 2022, 2030, 2040 e 2050, em montante total de R$7,8 bilhões.

final %>%
  slice(10) %>%
  mutate(integra = parcial(integra))

        DataReferencia       Titulo
1 2018-09-19T03:00:00Z 217ª Reunião
                                            LinkPagina Tipo
1 /content/copom/atascopom/COPOM217-not20180919217.pdf  pdf
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                integra
1 Ata da 217ª Reunião do\nComitê de Política Monetária (Copom) do\nBanco Central do Brasil\n18 e 19 de setembro de 2018\nBanco Central do Brasil                                                                217ª Reunião do Copom\nData: 18 e 19/9/2018\nLocal: Salas de reuniões do 8º andar (18/9) e do 20º andar (19/9) do Edifício-Sede do Banco Central do\nBrasil – Brasília – DF\nHorário de início e de término das sessões: 18/9: 10h08 – 11h59; 14h33 – 17h09\n                                             19/9: (.......) o Neves de\n                                                           Souza, Reinaldo Le Grazie, Sidnei Corrêa Marques e\n                                                           Tiago Couto Berriel.\nD) Decisão de política monetária\n28. Considerando o cenário básico, o balanço de riscos\ne o amplo conjunto de informações disponíveis, o\nCopom decidiu, por unanimidade, pela manutenção da\ntaxa básica de juros em 6,50% a.a. O Comitê entende\n                                                         5\n

final %>%
  slice(15) %>%
  mutate(integra = parcial(integra))

        DataReferencia       Titulo                      LinkPagina
1 2010-03-17T03:00:00Z 149ª Reunião /publicacoes/atascopom/17032010
  Tipo
1 html
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              integra
1 Sumário Evolução recente da economia Avaliação prospectiva das tendências da inflação Implementação da política monetária Inflação Atividade econômica Expectativas e sondagens Mercado de trabalho Crédito e inadimplência Ambiente externo Comércio exterior e reservas internacionais Mercado monetário e operações de mercado aberto Data: 16 e 17/03/2010 Local: Sala de reuniões do 8º andar (16/03) e do 20º andar (17/03) do Edifício-Sede do Banco Central do Brasil – Brasília – DF Horário de início: 16h (.......)  R$20,7 bilhões em Letras do Tesouro Nacional (LTN) com vencimentos em 2010, 2011 e 2012 e R$9,3 bilhões em Notas do Tesouro Nacional – Série F (NTN-F) com vencimentos em 2014, 2017 e 2021. As vendas de Letras Financeiras do Tesouro (LFT) totalizaram R$10,5 bilhões, com emissão de títulos com vencimentos em 2013 e 2015. Nos leilões de Notas do Tesouro Nacional – Série B (NTN-B), foram vendidos títulos com vencimentos em 2013, 2015, 2020, 2030, 2040 e 2050, em um montante total de R$14,5 bilhões.

final %>%
  slice(20) %>%
  mutate(integra = parcial(integra))

        DataReferencia      Titulo                      LinkPagina
1 1999-03-03T03:00:00Z 33ª Reunião /publicacoes/atascopom/03031999
  Tipo
1 html
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              integra
1 Sumário Preços e Nível de Atividade Agregados Monetários e Crédito Finanças Públicas Balanço de Pagamentos Ambiente Externo Evolução do Mercado de Câmbio Doméstico e Posição das Reservas Internacionais Liquidez Bancária Mercado Monetário e Operações de Mercado Aberto Nota Explicativa da Decisão do COPOM de 04/03/99 Data: 04.03.1999 Local: Sala de reuniões do 8º andar do Edifício-Sede do Banco Central - Brasília-DF Horário de início:11:15 h Horário de término:14:00 h Presentes: Membros da Diretor (.......) ias existentes, que, como se viu, são de origem cambial. Dessa forma, optou-se por uma taxa de 45% ao ano, mas com a introdução de um viés de redução, ou de baixa. A introdução desse viés se justifica pelo fato de o problema inflacionário de curto prazo no Brasil ter como origem a excessiva desvalorização cambial. Assim, na presença de sinais evidentes de retorno sustentado da taxa de câmbio a níveis mais realistas, não seria mais justificada a manutenção de taxas de juros nominais tão elevadas.

Após tirar a restrição de amostra e baixar todos os textos, vamos escrever nosso dataframe completo para usarmos futuramente em um próximo post explorando uma análise textual do conteúdo dessas atas. Para escrita de conteúdo que vai ser lido novamente no R, é sempre bom usar o pacote fst, além de comprimir o tamanho, a leitura e escrita é super rápida.


fst::write_fst(final, "./output/df_atas.fst")

Conclusões

A montagem da base foi razoavelmente simples, a maior dificuldade está em entender as APIs que o banco central utilizou para disponibilização das atas. Essa base pode ser uma fonte de informação valiosa para avaliar a história das decisões do Copom bem como tentar utilizá-la em cruzando com outras bases na tentativa de prever a reação do mercado frente às “entrelinhas” interpretadas nos textos das atas.

Em um próximo post vamos aplicar algumas técnicas de análise textual e tentar extrair informações interessantes desses textos.

via GIPHY

Citation

For attribution, please cite this work as

Guerra (2020, May 31). Fulljoin: Criando base de dados com as atas do Copom. Retrieved from https://www.fulljoin.com.br/posts/2020-05-31-atas-copom/

BibTeX citation

@misc{guerra2020criando,
  author = {Guerra, Saulo},
  title = {Fulljoin: Criando base de dados com as atas do Copom},
  url = {https://www.fulljoin.com.br/posts/2020-05-31-atas-copom/},
  year = {2020}
}