library(learnr)
library(magrittr)
library(readr)
knitr::opts_chunk$set(echo = TRUE,
                      out.width = "90%",
                      fig.align = "center")
tutorial_options(exercise.cap = "Código")

sampling_points <- readr::read_csv2("sampling_points.csv")

dados_billings <- readr::read_rds("dados_billings.rds")

pontos_billings <- c("PINH04100", "BILL02030", "BILL02100","BILL02500",
  "BITQ00100", "BILL02500",  "BILL02900", "RGDE02900", "BIRP00500",
  "RGDE02200", "RGDE02030"
)

Trabalho final para o curso 'Web Scraping'.
Beatriz Milz

Acesse o repositório no GitHub

Atualizado em r format(Sys.Date(), format='%d de %B de %Y').

Contextualização

Boas vindas! Esta página corresponde ao trabalho final para o curso Web Scraping, oferecido pela Curso-R e ministrado por Julio Trecenti e Caio Lente. O objetivo proposto para o trabalho final é construir um produto de dados que utilize Web Scraping.

Introdução

O monitoramento ambiental é, segundo a Empresa Brasileira de Pesquisa Agropecuária (EMBRAPA), "um processo de coleta de dados, estudo e acompanhamento contínuo e sistemático das variáveis ambientais, com o objetivo de identificar e avaliar - qualitativa e quantitativamente - as condições dos recursos naturais em um determinado momento, assim como as tendências ao longo do tempo".

A coleta de dados é representada na figura a seguir como a primeira etapa em um workflow de Ciência de Dados. A etapa de coleta de dados ambientais abrange diferentes tecnologias: por sensoriamento remoto, através de estações meteorológicas automáticas, coletas in situ, entre outros.

knitr::include_graphics("https://raw.githubusercontent.com/allisonhorst/stats-illustrations/master/openscapes/environmental-data-science-r4ds-general.png")

A coleta de amostras de águas superficiais é realizado in situ, ou seja, no local. Essas coletas e a posterior análise em laboratório das amostras são custosas para serem realizadas: requerem uma equipe para coletar e analisar as amostras, barcos para acessar os pontos, materiais e equipamentos, entre outros. Tanto a coleta quanto a análise das amostras de águas superficiais requerem critérios e metodologias específicas (é possível saber mais neste guia).

A Companhia Ambiental do Estado de São Paulo (CETESB) é a agência ambiental responsável pelo desenvolvimento de ações de controle, licenciamento, fiscalização e monitoramento das atividades potencialmente poluidoras no Estado de São Paulo*. Essa agência realiza o monitoramento da qualidade das águas das praias, rios, represas, do ar e do solo no Estado de São Paulo.

Os dados referentes ao monitoramento da qualidade do ar são disponibilizados no sistema Qualar, e o sistema Infoaguas disponibiliza dados referentes à qualidade da água. Entretanto, não existe uma API (Application Programming Interface) pública para acesso dessas informações, e ambos os sistemas foram elaborados de forma que obter informações para um amplo recorte espacial e temporal pode ser trabalhoso, requerendo bastante trabalho manual.

pontos_ativos <- sampling_points %>% 
  dplyr::filter(is.na(data_fim))

O pacote Rpollution, desenvolvido por @R-Rpollution, disponibiliza funções para obter os dados do sistema Qualar utilizando a linguagem de programação R e técnicas de Web Scraping. Entretanto, não foi encontrado alguma ferramenta similar para obtenção dos dados disponibilizados no sistema Infoaguas. Esses dados são importantes para acompanhar a situação de qualidade dos principais mananciais de abastecimento público do Estado de São Paulo*.

Segundo os dados disponibilizados no sistema Infoaguas, atualmente existem r nrow(pontos_ativos) pontos de coleta ativos no Estado de São Paulo.

Portanto, o objetivo deste trabalho foi desenvolver funções que possibilitem acessar os dados disponibilizados no sistema Infoaguas para Águas Superficiais, para que pessoas pesquisadoras, jornalistas, e outras interessadas possam ter acesso à estes dados de forma automatizada.

Pacotes utilizados

listar_pacotes <- function(vetor) {
  vetor %>% tibble::as_tibble() %>% dplyr::arrange(value) %>%
    dplyr::mutate(citacao = glue::glue("`{value}` [@R-{value}]")) %>%
    dplyr::summarise(citacao_completa = knitr::combine_words(citacao, and = "e ")) %>%
    dplyr::pull()

}

pacotes_funcoes <-
  c(
    "httr",
    "magrittr",
    "xml2",
    "purrr",
    "dplyr",
    "rvest",
    "janitor",
    "tibble",
    "progressr",
    "stringr",
    "lubridate",
    "glue",
    "abjutils",
    "readr",
    "biogeo"
  )
pacotes_usados_funcoes <- listar_pacotes(pacotes_funcoes)


pacotes_relatorio <-
  c("learnr",
    "knitr",
    "readxl",
    "DT",
    "rmarkdown",
    "usethis",
    "geobr" ,
    "sf")
pacotes_usados_relatorio <- listar_pacotes(pacotes_relatorio)

Nas funções desenvolvidas neste trabalho, foram usados dos seguintes pacotes: r pacotes_usados_funcoes.

Além destes, para a elaboração deste relatório também foi utilizado os pacotes r pacotes_usados_relatorio.

Acessando os dados

Para demonstrar como funciona o acesso manual no sistema Infoaguas, a seguir estão algumas screenshots que demonstram o fluxo de navegação no site até que seja possível obter os dados.

  1. Ao acessar o Sistema INFOAGUAS (através do link https://sistemainfoaguas.cetesb.sp.gov.br/ ), é solicitado a autenticação através de login e senha. Caso não tenha um cadastro, é possível realizar através do botão "Novo Usuário".
knitr::include_graphics("images/infoaguas_login.png")
  1. Após a autenticação, o site direciona para uma página de boas vindas. Para acessar os dados referentes à Águas Superficiais (como rios e reservatórios), é necessário clicar em: "Águas Superficiais > Consultas e Relatórios > Qualidade das Águas Superficiais".
knitr::include_graphics("images/infoaguas_3.PNG")
  1. O site direciona para uma página com um formulário de pesquisa, onde é possível fazer a pesquisa:
  2. Por ponto de monitoramento
  3. Por parâmetro.

Neste mesmo formlário, é possível filtrar por:

Neste exemplo realizaremos a pesquisa por ponto de monitoramento, e por UGRHI, escolhendo Alto Tietê.

knitr::include_graphics("images/infoaguas_5.PNG")
  1. Após clicar em "Buscar" o site direciona para uma página com uma tabela contendo informações sobre os pontos de monitoramento. É uma tabela interativa (feita com DataTables), onde há um campo que possibilita pesquisar algum termo na tabela.
knitr::include_graphics("images/infoaguas_7.png")
  1. Neste exemplo, a pesquisa foi feita com o termo 'Billings', para buscar pontos de monitoramento no Reservatório Billings, resultando em 4 pontos.
knitr::include_graphics("images/infoaguas_8.png")
n_pesquisas <-
  sampling_points %>% dplyr::filter(cod_ponto %in% pontos_billings) %>%
  dplyr::mutate(
    data_final = dplyr::case_when(is.na(data_fim) ~ Sys.Date(),
                                  TRUE ~ data_fim),
    tempo_operacao = data_final - data_inicio,
    anos_operacao = as.double(tempo_operacao / 365),
    pesquisas = ceiling(anos_operacao / 5)
  )


total_pesquisas_billings <-
  n_pesquisas %>% 
  dplyr::summarise(sum(pesquisas)) %>%
  dplyr::pull()
  1. Ao selecionar o botão (radio button) correspondente ao ponto de monitoramento, é solicitado informar o período da consulta, preenchendo a data inicial e a data final.

Importante destacar que o formulário limita este período para um intervalo de tempo de até 5 anos, o que implica que a obtenção de todos os dados disponíveis para a Represa Billings manualmente necessitaria que a pesquisa fosse feita r total_pesquisas_billings vezes!

knitr::include_graphics("images/infoaguas_9.png")
  1. Após informar um período válido, aparece uma caixa onde é possível realizar o download da base de dados em formato .xlsx .
knitr::include_graphics("images/infoaguas_10.PNG")

Exemplo do arquivo obtido:

knitr::include_graphics("images/infoaguas_dataset.PNG")

A base de dados disponibilizada neste exemplo apresenta medições referentes à diversos parâmetros (porém na base completa existem mais parâmetros):

pesquisa_infoaguas_exemplo <- readxl::read_excel("pesquisa_infoaguas_exemplo.xlsx")
pesquisa_infoaguas_exemplo %>% 
  janitor::clean_names() %>%
  dplyr::group_by(tipo_parametro) %>%  
  dplyr::distinct(parametro) %>% 
  dplyr::arrange(tipo_parametro, parametro) %>% 
  dplyr::relocate(tipo_parametro, .before = parametro) %>% 
  dplyr::summarise(parametros = knitr::combine_words(parametro, and = "e ")) %>% 
  knitr::kable(col.names = c("Tipo de parâmetro", "Parâmetros"))

Funções desenvolvidas

A seguir, apresento uma breve descrição das funções desenvolvidas neste trabalho.

Autenticação no sistema

O sistema Infoaguas solicita login para acessar os dados. Portanto, primeiramente é necessário realizar a autentição.

A função login_infoaguas() tem como argumentos o email (login) e a senha (password), e realiza a autenticação no sistema Infoaguas através de uma requisição do tipo POST.

login_infoaguas(login =  ... ,
                password = ...)

Obter pontos de coleta

Para possibilitar a realização das buscas de resultados de parâmetros para os pontos de monitoramento, é necessário ter informações sobre os pontos de monitoramento. A função get_sampling_points() realiza um Web Scraping e retorna uma base contendo informações sobre os pontos. Obs: Essa base será descrita posteriormente. Não é necessário informar argumentos para essa função.

get_sampling_points() 

Buscar dados de qualidade da água

Para buscar os dados, foram desenvolvidas duas funções principais:

get_results(sampling_point = ... , path = "..../")
get_all_results(points = ... , path = "..../")

Ao obter os dados, não é necessário limitar o período de busca para 5 anos. A função foi desenvolvida para fazer a busca por todos os dados ao longo do tempo (desde o início do funcionamento do ponto, até atualmente).

Arrumar as bases

A última função desenvolvida se chama tidy_infoaguas(), e tem como argumento o path, sendo o diretório onde os arquivos foram salvos ao executar a função anterior. Essa função irá buscar todos os arquivos .xlsx neste diretório, irá ler os dados, e realizar algumas operações para limpar a base. A função retorna a base de dados arrumada. A base já vem em formato tidy, sendo necessário apenas renomear o nome das colunas, e alterar o tipo de algumas colunas.

tidy_infoaguas(path = "..../")

Bases de dados obtidas

Pontos de coleta

A primeira base obtida é a dos pontos de coleta. Possui as seguintes variáveis:

DT::datatable(sampling_points)

Dados de qualidade da água

A base obtida utilizando as funções desenvolvidas neste trabalho apresenta dados para todos os pontos de monitoramento, para todos os parâmetros, em todo o período de operação. Por este motivo, a base tem quase 2 milhões de observações, contendo as seguintes variáveis:

# > dplyr::glimpse(dados_infoaguas)
# Rows: 1,921,122
# Columns: 30
# $ periodo_de              <date> 1977-11-01, 1977-11-01, 1977-11-01, 1977-11-01, 1977-11-01,...
# $ periodo_ate             <date> 2020-11-28, 2020-11-28, 2020-11-28, 2020-11-28, 2020-11-28,...
# $ cod_interaguas          <chr> "100", "100", "100", "100", "100", "100", "100", "100", "100...
# $ tipo_rede               <chr> "Rede Básica", "Rede Básica", "Rede Básica", "Rede Básica", ...
# $ ugrhi                   <chr> "06 - ALTO TIÊTE", "06 - ALTO TIÊTE", "06 - ALTO TIÊTE", "06...
# $ codigo_ponto            <chr> "COGR00900", "COGR00900", "COGR00900", "COGR00900", "COGR009...
# $ status_ponto            <chr> "Ativo", "Ativo", "Ativo", "Ativo", "Ativo", "Ativo", "Ativo...
# $ data_coleta             <date> 1978-01-01, 1978-04-01, 1978-05-01, 1978-07-01, 1978-09-01,...
# $ hora_coleta             <Period> 12H 0M 0S, 12H 0M 0S, 12H 0M 0S, 12H 0M 0S, 12H 0M 0S, 12...
# $ parametro               <chr> "pH", "pH", "pH", "pH", "pH", "pH", "pH", "pH", "pH", "pH", ...
# $ sinal                   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
# $ valor                   <chr> "6,40000000", "7,20000000", "6,80000000", "6,50000000", "6,5...
# $ valor_numerico          <dbl> 6.4, 7.2, 6.8, 6.5, 6.5, 6.7, 6.6, 6.9, 6.4, 6.4, 6.8, 5.0, ...
# $ valor_texto             <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...
# $ unidade                 <chr> "U.pH", "U.pH", "U.pH", "U.pH", "U.pH", "U.pH", "U.pH", "U.p...
# $ tipo_parametro          <chr> "3- Químicos", "3- Químicos", "3- Químicos", "3- Químicos", ...
# $ sistema_hidrico         <chr> "Reservatório das Graças - COGR", "Reservatório das Graças -...
# $ tipo_de_sistema_hidrico <chr> "Reservatório (Lêntico)", "Reservatório (Lêntico)", "Reserva...
# $ classe                  <chr> "Classe Especial", "Classe Especial", "Classe Especial", "Cl...
# $ municipio               <chr> "COTIA", "COTIA", "COTIA", "COTIA", "COTIA", "COTIA", "COTIA...
# $ uf                      <chr> "SP", "SP", "SP", "SP", "SP", "SP", "SP", "SP", "SP", "SP", ...
# $ inicio_operacao         <date> 1977-11-01, 1977-11-01, 1977-11-01, 1977-11-01, 1977-11-01,...
# $ fim_operacao            <date> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
# $ latitude                <chr> "23 39 12", "23 39 12", "23 39 12", "23 39 12", "23 39 12", ...
# $ longitude               <chr> "46 58 03", "46 58 03", "46 58 03", "46 58 03", "46 58 03", ...
# $ altitude                <dbl> 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, ...
# $ localizacao             <chr> "Na barragem, junto à captação do Alto Cotia", "Na barragem,...
# $ captacao                <chr> "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", ...
# $ latitude_decimal        <dbl> -23.65333, -23.65333, -23.65333, -23.65333, -23.65333, -23.6...
# $ longitude_decimal       <dbl> -46.9675, -46.9675, -46.9675, -46.9675, -46.9675, -46.9675, ...

Para não sobrecarregar o relatório, será apresentado uma tabela de exemplo conendo apenas os dados referentes à Represa Billings. Exemplo da busca utilizando funções desenvolvidas neste trabalho:

# Autenticar
infoaguas::login_infoaguas(login = Sys.getenv("CETESB_LOGIN"), 
                 password =  Sys.getenv("CETESB_PWD"))

pontos_billings <- c("PINH04100", "BILL02030", "BILL02100","BILL02500",
  "BITQ00100", "BILL02500",  "BILL02900", "RGDE02900", "BIRP00500",
  "RGDE02200", "RGDE02030")

# Definir os pontos para obter os dados
codigos <-
  sampling_points %>% 
  dplyr::filter(cod_ponto %in% pontos_billings) %>%
  dplyr::pull(cod_interaguas)

# Definir o diretório onde serão salvos os arquivos
path_billings <- "billings/"

# Obter os arquivos em excel com dados para cada ponto
get_all_results(codigos, path_billings)

# Organizar todos os excel em uma base arrumada
dados_billings <- tidy_infoaguas(path_billings)

# Salvar esses dados em um csv
readr::write_rds(dados_billings, "dados_billings.rds")

A base de exemplo, contendo apenas os dados referentes à Represa Billings, possui cerca de r ceiling(nrow(dados_billings)/1000) mil observações e r ncol(dados_billings) variáveis. A base a seguir é uma amostra da tabela obtida:

DT::datatable(head(dados_billings))

Exemplo de uso dos dados

Para exemplificar o uso dos dados obtidos, será realizada uma comparação dos dados de qualidade da água da Represa Billings com os padrões apresentados na Resolução CONAMA 357 nº 2005 para os parâmetros: pH, oxigênio dissolvido e clorofila-a.

A Resolução CONAMA 357 nº 2005 classifica os corpos hídricos em classes, e estabelece usos e padrões de qualidade adequados para cada classe.

As classes são:

conama357 <- readxl::read_excel("conama357.xlsx")
conama357 %>% knitr::kable(col.names = c("Classe", "Usos da água"))

Abaixo segue um mapa onde estão apresentados os pontos de coleta na represa Billings, sendo que o a cor do marcador do ponto representa a classe:

library(leaflet)

paleta <- RColorBrewer::brewer.pal(3, "Set1")

coordenadas <-
  dados_billings %>% dplyr::distinct(longitude_decimal,
                                     latitude_decimal,
                                     ugrhi,
                                     codigo_ponto,
                                     sistema_hidrico, classe) %>%
  dplyr::mutate(
    texto = glue::glue(
      "Código do ponto: {codigo_ponto}  <br> Sistema Hídrico: {sistema_hidrico} <br>
                                       UGRHI: {ugrhi} <br>
      Classe (segundo o Infoaguas): {classe}"
    ),
    cores = dplyr::case_when(classe == "Classe Especial" ~ paleta[1],
                             classe == "Classe 2" ~ paleta[2],
                             classe == "Classe 4" ~ paleta[3])
  )

 leaflet::leaflet(coordenadas) %>%
 addTiles() %>%
 addCircleMarkers(~longitude_decimal,  ~latitude_decimal, popup = ~texto, color = ~cores)

No gráfico a seguir, está apresentada a conformidade (ou não) das amostras em relação aos padrões definidos na Resolução, segundo a classe do ponto, para os parâmetros Clorofila-a, pH e Oxigênio Dissolvido coletados desde 2015:

billings_conformidade <- dados_billings %>% 
  dplyr::filter(parametro %in% c("Oxigênio Dissolvido", "pH", "Clorofila-a")) %>%
  dplyr::mutate(
    ano = lubridate::year(data_coleta),
    conformidade_conama = dplyr::case_when(

      # OD -----------------------------------
      parametro == "Oxigênio Dissolvido" &
        classe == "Classe 4" & valor_numerico >= 2 ~ "Conforme",
      parametro == "Oxigênio Dissolvido" &
        classe == "Classe 4" & valor_numerico < 2 ~ "Não conforme",


      parametro == "Oxigênio Dissolvido" &
        classe == "Classe 2" & valor_numerico >= 5 ~ "Conforme",
      parametro == "Oxigênio Dissolvido" &
        classe == "Classe 2" & valor_numerico < 5 ~ "Não conforme",


            parametro == "Oxigênio Dissolvido" &
        classe == "Classe Especial" & valor_numerico >= 6 ~ "Conforme",
      parametro == "Oxigênio Dissolvido" &
        classe == "Classe Especial" & valor_numerico < 6 ~ "Não conforme",



      # pH ---------
      parametro == "pH" & valor_numerico >= 6 & valor_numerico <= 9 ~ "Conforme",


        parametro == "pH" & valor_numerico < 6  ~ "Não conforme",

          parametro == "pH" &  valor_numerico > 9 ~ "Não conforme",


         # Clorofila-a  -----------------------------------
      parametro == "Clorofila-a" &
        classe == "Classe 4"  ~ "Padrão não especificado na legislação",


      parametro == "Clorofila-a" &
        classe == "Classe 2" & valor_numerico <= 30 ~ "Conforme",
      parametro == "Clorofila-a" &
        classe == "Classe 2" & valor_numerico > 30 ~ "Não conforme",


            parametro == "Clorofila-a" &
        classe == "Classe Especial" & valor_numerico <= 10 ~ "Conforme",
      parametro == "Clorofila-a" &
        classe == "Classe Especial" & valor_numerico > 10 ~ "Não conforme",
    ),
    nome = glue::glue("{classe} - {codigo_ponto}")
  ) %>% 
  dplyr::filter(ano >= 2015)

library(ggplot2)
billings_conformidade %>% 
  dplyr::count(parametro, ano, data_coleta, conformidade_conama, nome,  codigo_ponto, classe) %>% 
  ggplot() +
  geom_col(aes(y = nome, x = n, fill = conformidade_conama)) +
  facet_wrap(~ parametro, scales = "free_x", nrow = 3) +
  theme_bw() +
  viridis::scale_fill_viridis(discrete = TRUE, direction = -1) +
  labs( y = "Classe e código do ponto de coleta de amostras",
        x = "Número de análises", fill = "Conformidade com os valores definidos na \n Resolução CONAMA 357/2005") +
    theme(legend.position="bottom")

Conclusões

Próximos passos/ Melhorias

Agradecimentos

knitr::include_graphics("https://media.giphy.com/media/3oz8xIsloV7zOmt81G/giphy.gif")

Referências

# knitr::write_bib(c('Rpollution', pacotes_funcoes, pacotes_relatorio), 'packages.bib')


beatrizmilz/infoaguas documentation built on April 18, 2021, 1:19 a.m.