Baixando dados de tabelas

Apesar do uso cada vez mais difundido das API (“Application Programming Interface”) para obter dados via internet, ainda é comum a disponibilização de dados através de tabelas em arquivos de planilhas (do tipo Microsoft Excel ou mesmo HTML). Já foram publicadas rotinas em shell script e script em R para abrir arquivos no formato XLS(X) para extrair informações disponíveis nos arquivos para uso interno ou gravar a saída em um arquivo CSV.

Os scripts a seguir foram escritos em python para baixar um arquivo HTML (ou XLSX) e extrair as informações. Como exemplo, são usados arquivos do ONS, com o objetivo de extrair os nomes dos reservatórios e valores dos volumes úteis.

Primeiramente, deve-se montar o link a ser consultado, recebendo data e número do subsistema, assim como o nome do arquivo a ser gravado no computador. Para baixar o arquivo, é usada a biblioteca “urllib“.

O script a seguir baixa uma arquivo HTML e seu conteúdo é interpretado pela biblioteca “BeautifulSoup“. Outro exemplo de uso dessa lib pode ser visto no post Leitura automática de páginas com envio de informações. A função “findAll” busca por tags HTML, podendo restringir por seus atributos (como “id” ou “class”). Ao encontrar uma tabela (tag “table”), as linhas (“tr”, de “table row”) e células (“td” ou “th”, de “table head”) podem ser selecionadas por colunas.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
from datetime import datetime
import urllib
from bs4 import BeautifulSoup

path = os.path.dirname(os.path.realpath(__file__))

# Montar link
#data = "{:%Y_%m_%d}".format(datetime.now())
data = '2018_09_01'
sub = 24
link = "http://sdro.ons.org.br/SDRO/DIARIO/%s/HTML/%s_SituacaoPrincipaisReservatorios_Regiao.html" %(data,sub)
html_file = "%s/temp_ons/volume_util.html" %path

# Baixar arquivo
#testfile = urllib.URLopener()
#testfile.retrieve(link, html_file)

# Buscar valores por coluna
soup = BeautifulSoup(open(html_file), "html.parser")
table = soup.find("table", attrs={"id":"gridViewSituacaoPrincipaisReservatorios"})
# Busca somente nomes com restrições e guarda em vetor
#names = soup.find_all('td', {'class' : 'fonte_itens_situacao_principais_reservatorios', 'style' : 'WIDTH: 120px' })

# Varrer tabela e imprimir conteúdo
for row in soup.findAll('table')[0].tbody.findAll('tr'):
	#print(row)
	size = len(row.findAll('td'))
	if size > 0:
		first_column = row.findAll('td')[0].contents
		third_column = row.findAll('td')[2].contents
	else:
		first_column = row.findAll('th')[0].contents
		third_column = row.findAll('th')[2].contents
	print(first_column)
	print(third_column)
	print('------')
	#exit()

A variável “size” e a condicional a seguir foram feitas para o caso da célula ter a tag “td” ou “th”.

O segundo script baixa um arquivo do tipo XLSX, que é lido e interpretado diretamente pela biblioteca “pandas“, guardando os valores em um “dataframe”. Também foi incluído um loop para quatro valores diferentes de subsistemas.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import urllib
import pandas as pd

path = os.path.dirname(os.path.realpath(__file__))

# Montar strings de datas
data1 = '2018_10_13'
data2 = '13-10-2018'

# Loop de subsistemas: SE-24; S-23; NE-25; N-26
for sub in range(23,27):
	print(sub)
	# Montar link
	link = "http://sdro.ons.org.br/SDRO/DIARIO/%s/HTML/%s_SituacaoPrincipaisReservatorios_Regiao_%s.xlsx" %(data1, sub, data2)
	file_name = "%s/temp_ons/volume_util.xlsx" %path
	# Baixar arquivo
	testfile = urllib.URLopener()
	testfile.retrieve(link, file_name)
	
	# Ler arquivo para dataframe
	dfs = pd.read_excel(file_name)
	# Selecionar colunas com nome do reservatório e volume útil; da 5a linha pra frente
	df = dfs.iloc[5:, [1,4]]
	# Tirar linhas indefinidas
	#df = df.dropna()
	# Renomear colunas
	df.columns = ['reservatorio', 'vol_util']
	
	# Gravar tabela em arquivo CSV - dar append se não for o primeiro subsistema
	file_out = "%s/temp_ons/volume_util_%s.csv" %(path,data1)
	if sub == 23:
		df.to_csv(file_out, index=False, encoding='utf-8')
	else:
		dff = pd.read_csv(file_out, encoding='utf-8')
		dff = dff.append(df)
		dff.to_csv(file_out, index=False, encoding='utf-8')

A condicional serve para criar um novo arquivo, se for o primeiro subsistema, ou para incluir os novos valores no final do arquivo já criado (sem o cabeçalho).

2 comments

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.