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')
.
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.
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.
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
.
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.
knitr::include_graphics("images/infoaguas_login.png")
knitr::include_graphics("images/infoaguas_3.PNG")
Neste mesmo formlário, é possível filtrar por:
Todos (sem filtro)
UGRHI (Unidade de Gerenciamento de Recursos Hídricos. Por exemplo: Alto Tietê)
Sistema Hídrico (por exemplo: Represa Billings)
Município
Neste exemplo realizaremos a pesquisa por ponto de monitoramento, e por UGRHI, escolhendo Alto Tietê.
knitr::include_graphics("images/infoaguas_5.PNG")
knitr::include_graphics("images/infoaguas_7.png")
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()
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")
.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"))
A seguir, apresento uma breve descrição das funções desenvolvidas neste trabalho.
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 = ...)
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()
Para buscar os dados, foram desenvolvidas duas funções principais:
get_results()
: tem como argumento o sampling_point
(o número utilizado no sistema para se referir ao ponto de coleta), e o path
(um diretório onde os arquivos baixados serão salvos). get_results(sampling_point = ... , path = "..../")
get_all_results()
: tem como argumento points
, sendo um vetor contendo os pontos de coleta a qual deseja obter os dados, e o path
(um diretório onde os arquivos baixados serão salvos). Internamente, essa função utiliza a função get_results()
(descrita anteriormente). 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).
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 = "..../")
A primeira base obtida é a dos pontos de coleta. Possui as seguintes variáveis:
cod_ponto
: código do ponto de coleta apresentado no sistema Infoaguas.
sist_hidrico
: sistema hídrico onde o ponto está localizado.
localização
: texto que descreve onde o ponto de coleta está localizado.
data_inicio
e data_fim
: data de início e de fim da operação deste ponto de coleta. Na variável data_fim
, NA
representa um ponto de coleta que ainda está ativo.
municipio
e muni
: os dois correspondem ao nome do município onde o ponto está localizado.
code_muni
: código do município segundo o IBGE.
cod_interaguas
: código utilizado internamente no sistema, necessário para realizar as pesquisas.
DT::datatable(sampling_points)
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:
periodo_de
e periodo_ate
: período da pesquisa.
cod_interaguas
: código utilizado internamente no sistema, necessário para realizar as pesquisas.
tipo_rede
: Tipo de rede de monitoramento. Ex: Rede Básica.
ugrhi
: Unidade de Gerenciamento de Recursos Hídricos onde o ponto está localizado.
codigo_ponto
: código do ponto de coleta apresentado no sistema Infoaguas.
status_ponto
: informa se o ponto está ativo atualmente ou não.
data_coleta
e hora_coleta
: informações de quando a amostra foi coletada.
parametro
: parâmetro analisado. Ex. temperatura da água, oxigênio dissolvido, etc.
sinal
: alguns parâmetros apresentam sinal (Ex. menor que, maior que) junto ao resultado obtido na
análise do parâmetro.
valor
: valor resultante do parâmetro. É a coluna original.
valor_numerico
: valor resultante para os parâmetros que tem resultados numéricos. Coluna criada na etapa de limpeza dos dados.
valor_texto
: valor resultante para os parâmetros que tem resultados de texto. Coluna criada na etapa de limpeza dos dados.
unidade
: unidade de medida do valor resultante.
tipo_parametro
: Categoria do parâmetro (ex. Físico, Químico, Biológico, etc)
sistema_hidrico
: corpo hídrico onde a amostra foi coletada.
tipo_de_sistema_hidrico
: O tipo de sistema hídrico. Ex: Reservatório ou Rio.
classe
: classe do sistema_hidrico
segundo a Resolução CONAMA nº 357/2005.
municipio
: nome do município onde o ponto de coleta está localizado.
uf
: estado brasileiro onde o ponto está localizado.
inicio_operacao
e fim_operacao
: data de início e de fim da operação deste ponto de coleta. Na variável fim_operacao
, NA
representa um ponto de coleta que ainda está ativo.
latitude
e longitude
: Latitude e Longitude do ponto de coleta (em graus, minutos e segundos).
latitude_decimal
e longitude_decimal
: Latitude e Longitude do ponto de coleta (em graus decimais). Coluna criada na etapa de limpeza dos dados.
altitude
: altitude do ponto de coleta.
localização
: texto que descreve onde o ponto de coleta está localizado.
captacao
: Averiguar. Creio que está relacionado à proximidade de um ponto de captação de água para consumo humano, porém não está muito claro.
# > 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))
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")
Não consegui utilizar o pacote furrr
na função get_all_results()
. Seria interessante corrigir isso pois deixaria a função mais rápida.
Padronizar nome das funções, argumentos, variáveis etc em um único idioma. Alguns escrevi em inglês, outros em português, tá bagunçado.
Documentar as funções!
Pensar em uma forma de disponibilizar para a comunidade. Não sei se ficará nesse pacote, se ficar é necessário preencher o arquivo DESCRIPTION.
Desenvolvi funções para obter dados sobre o monitoramento das águas superficiais, porém no sistema existem também uma seção sobre águas subterrâneas. Seria interessante raspar também?
Aos professores do curso pelas aulas maravilhosas: Julio Trecenti e Caio Lente.
Post sobre o scraper do QUALAR - Por William Amorim
Para você que leu até aqui!
knitr::include_graphics("https://media.giphy.com/media/3oz8xIsloV7zOmt81G/giphy.gif")
# knitr::write_bib(c('Rpollution', pacotes_funcoes, pacotes_relatorio), 'packages.bib')
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.