Skip to content

Instantly share code, notes, and snippets.

@JeanFavaretto
Last active November 26, 2020 19:12
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save JeanFavaretto/58110021276b27d65e89 to your computer and use it in GitHub Desktop.
Save JeanFavaretto/58110021276b27d65e89 to your computer and use it in GitHub Desktop.
HidroWeb Baixar séries históricas, download, obtenção, aquisição, Estações, Pluviométricas, Pluviometria, Fluviométricas, Fluviometria, Precipitação, Vazão, Cotas, baixar varias estações. Este script, Python HidroWeb, foi criado para automatizar o procedimento de aquisição de dados das estações do portal: http://hidroweb.ana.gov.br/
# -*- coding: utf-8 -*-
"""
___________________________-> Python - Hidroweb <-______________________________
Autor: Arthur Alvin 25/04/2015
afmalvim@gmail.com
Modificação: Jean Favaretto 16/07/2015
jeanfavaretto@gmail.com
Modificação:Vitor Gustavo Geller 16/07/2015
vitorgg_hz@hotmail.com
______________________________-> Comentários <-_________________________________
O script Python HidroWeb foi criado para automatizar o procedimento de aquisição
de dados das estações do portal: http://hidroweb.ana.gov.br/
Para utilizar o script deverao ser instaladas as bibliotecas:
-> requests
-> beautifulsoup4 (ou superior)
UTILIZACAO:
Apos a instalacao das bibliotecas cria-se um Arquivo de Entrada, com o numero
das estacoes. A proxima etapa será inicilizar o script, entao ele abrir uma
janela para selecionar o Arquivo de Entrada. Como saída o HidroWeb - Python,
retorna duas informacoes. A primeira em tela, contendo a situacao do download.
Por fim, gera-se no mesmo diretorio do Arquivo de Entrada, os arquivos de cada
estacao que foi possivel realizar a transferencia (baixada).
ARQUIVO DE ENTRADA:
A entrada deve ser um arquivo *.txt contendo o número das estação a serem
baixadas, com a seguinte estrutura:
-> O número das estacoes defem ser digitadas linhas apos linhas,
sem cabecalhos, sem espacos, nem separadores (, . ;).
-> Simplismente um Enter após cada numero de estacao.
02751025
02849035
02750004
02650032
02850015
SAIDAS:
Situação das transferencias em Tela:
** 02851050 **
** 02851050 ** (baixado)
** 02851050 ** (concluído)
No diretorio do Arquivo de Entrada serao criados os arquivos de saida contendo
a informacao disponivel de cada estacao baixada.
OBS: Tenha certeza que todos numeros das estacao existam, caso contrario da
"BuuuG".
Palavras chave: HidroWeb, ANA, Estacoes, Pluviometricas, Fluviometricas,
Precipitacao, Vazao, Cotas, baixar, download.
"""
# ******** DECLARACOES INICIAIS
import os
import Tkinter, tkFileDialog
import sys
import requests
import re
import shutil
from bs4 import BeautifulSoup
# By Vitor
# ABRE ARQUIVO DE ENTRADA
root = Tkinter.Tk()
entrada = tkFileDialog.askopenfile(mode='r')
root.destroy()
#****************---------------correcao de bug--------------********************
if (entrada == None):
sair = raw_input('\tArquivo de entrada nao selecionado. \n\t\tPressione enter para sair.\n')
sys.exit()
#****************---------------fim da correcao--------------********************
pathname = os.path.dirname(entrada.name) #define o path de trabalho igual ao do arquivo de entrada
os.chdir(pathname) #muda caminho de trabalho.
VALORES = []
# By Jean
while True:
conteudo_linha = entrada.read().split("\n")
VALORES.append(conteudo_linha)
if (len(conteudo_linha) <= 1):
break
print VALORES, "\n"
#### By Arthur
class Hidroweb(object):
url_estacao = 'http://hidroweb.ana.gov.br/Estacao.asp?Codigo={0}&CriaArq=true&TipoArq={1}'
url_arquivo = 'http://hidroweb.ana.gov.br/{0}'
def __init__(self, estacoes):
self.estacoes = estacoes
def montar_url_estacao(self, estacao, tipo=1):
return self.url_estacao.format(estacao, tipo)
def montar_url_arquivo(self, caminho):
return self.url_arquivo.format(caminho)
def montar_nome_arquivo(self, estacao):
return u'{0}.zip'.format(estacao)
def salvar_arquivo_texto(self, estacao, link):
r = requests.get(self.montar_url_arquivo(link), stream=True)
if r.status_code == 200:
with open(self.montar_nome_arquivo(estacao), 'wb') as f:
r.raw.decode_content = True
shutil.copyfileobj(r.raw, f)
print '** %s ** (baixado)' % (estacao, )
else:
print '** %s ** (problema)' % (estacao, )
def obter_link_arquivo(self, response):
soup = BeautifulSoup(response.content)
return soup.find('a', href=re.compile('^ARQ/'))['href']
def executar(self):
post_data = {'cboTipoReg': '10'}
for est in self.estacoes:
print '** %s **' % (est, )
r = requests.post(self.montar_url_estacao(est), data=post_data)
link = self.obter_link_arquivo(r)
self.salvar_arquivo_texto(est, link)
print '** %s ** (concluído)' % (est, )
if __name__ == '__main__':
estacoes = VALORES[::1][0]
hid = Hidroweb(estacoes)
hid.executar()
@anahelfer
Copy link

Olá Jean, tudo bem?
tentei utilizar o seu script para aquisição de dados fluviométricos cujas estações são compostos por 8 dígitos (exemplo: 64323000) do Hidroweb e dá a seguinte mensagem: TypeError: 'NoneType' object has no attribute 'getitem' Poderia me explicar como resolvo? Grata, Ana

@camilascardoso
Copy link

Olá Jean

Eu tive o mesmo erro da AnaHelfer. Poderia me ajudar?

@JeanFavaretto
Copy link
Author

Prezadas Ana e Camila, desculpe a demora pela resposta.
Há uma alteração que deve ser feita na linha 139. A variável post_data varia de acordo com os dados de interesse veja os casos:
post_data = {'cboTipoReg': '10'} # para chuvas
post_data = {'cboTipoReg': '8'} # para cotas
post_data = {'cboTipoReg': '9'} # para vazões
post_data = {'cboTipoReg': '12'} # qualidade da água
post_data = {'cboTipoReg': '13'} # resumo de descarga
post_data = {'cboTipoReg': '16'} # perfil transversal

Ainda não tive tempo para atualizar a rotina. Boa sorte e bom trabalho!

@gsmohor
Copy link

gsmohor commented May 11, 2016

Caro Jean e demais.
Trabalhei um pouquinho e achei uma solução. Pode não ser a melhor pra todo mundo, mas para mim foi a melhor.

Coloquei um loop para baixar todos os tipos de dados, conforme sua sugestão acima. Como nem todas as estações têm todos os tipos de dados, ele retornaria um erro e travaria. Eu coloquei um try:except, e segue o código caso não tenha o arquivo. E como os arquivos são zips e os txts dentro tem nome simples, resolvi criar uma pasta para cada estação e deszipar os arquivos para dentro da pasta.
Assim, rodado o script, você terá uma pasta para cada estação com todos os arquivos disponíveis.

******** DECLARACOES INICIAIS

import os
import Tkinter, tkFileDialog
import sys
import requests
import re
import shutil
import zipfile
from bs4 import BeautifulSoup

By Vitor

ABRE ARQUIVO DE ENTRADA

root = Tkinter.Tk()
entrada = tkFileDialog.askopenfile(mode='r')
root.destroy()

_---------------correcao de bug--------------_****

if (entrada == None):
sair = raw_input('\tArquivo de entrada nao selecionado. \n\t\tPressione enter para sair.\n')
sys.exit()

_---------------fim da correcao--------------_****

pathname = os.path.dirname(entrada.name) #define o path de trabalho igual ao do arquivo de entrada
os.chdir(pathname) #muda caminho de trabalho.
Pastaatual=os.getcwd()

VALORES = []

By Jean

while True:

conteudo_linha = entrada.read().split("\n")
VALORES.append(conteudo_linha)

if (len(conteudo_linha) <= 1):
    break

print VALORES, "\n"

By Arthur

class Hidroweb(object):

url_estacao = 'http://hidroweb.ana.gov.br/Estacao.asp?Codigo={0}&CriaArq=true&TipoArq={1}'
url_arquivo = 'http://hidroweb.ana.gov.br/{0}'

def __init__(self, estacoes):
    self.estacoes = estacoes

def montar_url_estacao(self, estacao, tipo=1):
    return self.url_estacao.format(estacao, tipo)

def montar_url_arquivo(self, caminho):
    return self.url_arquivo.format(caminho)

def montar_nome_arquivo(self, estacao):
    return u'{0}.zip'.format(estacao)

def salvar_arquivo_texto(self, estacao, link):
    r = requests.get(self.montar_url_arquivo(link), stream=True)
    if r.status_code == 200:
        with open(self.montar_nome_arquivo(estacao), 'wb') as f:
            r.raw.decode_content = True
            shutil.copyfileobj(r.raw, f)
   ## BY GUILHERME
        ## cria pasta para cada extacao e extrai os zips de cada variavel
        if not os.path.exists(str(estacao)):
            os.makedirs(str(estacao))
        else:
            print 'pasta já existe'
        filezip = open(str(estacao)+'.zip', 'rb')
        zipp = zipfile.ZipFile(filezip)
        for name in zipp.namelist():
            zipp.extract(name,Pastaatual+'\\'+str(estacao)+'\\')
        filezip.close()
        ##   
        print '** %s ** (baixado)' % (estacao, )
    else:
        print '** %s ** (problema)' % (estacao, )

def obter_link_arquivo(self, response):
    soup = BeautifulSoup(response.content, "html.parser")

BY GUILHERME

    ## procura pelo arquivo, mas se der erro, continua
    try:
      soup.find('a', href=re.compile('^ARQ/'))['href']
      return soup.find('a', href=re.compile('^ARQ/'))['href']
    except Exception:
      print 'Dados nao encontrados deste tipo nesta estacao'
      pass
    ##
    return # soup.find('a', href=re.compile('^ARQ/'))['href']
def executar(self):
    ##loop com todos os tipos de dados
    tipos=[(8,'Cotas'),(9,'Vazão'),(10,'Chuva'),(12,'Qualidade'),(13,'ResumoDesc'),(16,'Perfil Transv')]
    for tipoi in tipos:
        print '\n ',tipoi[0],' buscando dasdos de ',tipoi[1],'\n'
        post_data = {'cboTipoReg': tipoi[0]}       
        for est in self.estacoes:
            print '** %s **' % (est, )
            r = requests.post(self.montar_url_estacao(est), data=post_data)
            link = self.obter_link_arquivo(r)
            if link is not None:
                self.salvar_arquivo_texto(est, link)
                print '** %s ** (concluído)' % (est, )

if name == 'main':
estacoes = VALORES[::1][0]
hid = Hidroweb(estacoes)
hid.executar()

@vanessaha
Copy link

Não consegui fazer funcionar...

136 def executar(self):

TypeError: 'NoneType' object has no attribute 'getitem'

O que será q tem q fazer?
No meu caso só quero dados de chuva mesmo...

@jaovssilva
Copy link

Olá! estou tentando usar o código, porém, a atualizou os links. Poderia atualizar o código tb? tentei fazer por contra própria e não consegui

@duartejr
Copy link

Este script permite o download de dados pluviométricos e fluviométricos do novo HidroWeb.
https://github.com/duartejr/pyHidroWeb.git

@marcelobrunolara
Copy link

Olá,

parece que o HidroWeb foi completamente atualizado e os serviços disponíveis via aspnet foram removidos. Está usando Java EE agora. Existe algum workaround já implementado ou algum serviço exposto por eles?

@DaniloBN
Copy link

DaniloBN commented May 5, 2018

Alguém já conseguiu tornar o código funcional para a atualização do site?

@dvictori
Copy link

Opa, também estou interessado em acessar os dados do HidroWeb via script. Mas com a nova versão do HidroWeb, os scripts pararam de funcionar. Alguém conseguiu baixar os dados?

@leo8nardo8
Copy link

Boa noite, tenho interesse em baixar dados de várias estações via script também. Alguém conseguiu baixar dados no novo portal?

@ecotecnologias
Copy link

Duartejr, tentamos rodar seu código e não conseguimos. É para o python 2.7 ou já está no python 3? Já está rodando no novo Hidroweb?

@duartejr
Copy link

Atualizado script para download de dados do portal Hidroweb.
https://github.com/duartejr/pyHidroWeb.git
O script foi testado para Python 3 em sistema operacional Linux.

@guilhermedcastro
Copy link

guilhermedcastro commented Dec 13, 2018

Olá @duartejr, estou tentando adaptar o seu código para windows, mas estou constantemente recebendo uma mensagem de erro de identação na linha de exceções do final da função download_hidroweb.
Pra fazer o código rodar, eu criei um método fcntl conforme orientações de um fórum da internet, dado que eu estava rodando em windows e esse método não possui equivalente direto.

Segue meu código adaptado para avaliação e sugestões:

`import fcntl
import os
from tkinter import filedialog
import sys
import requests
import re
import shutil
import portalocker
import xvfbwrapper
from bs4 import BeautifulSoup
import time
from pyvirtualdisplay import Display
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
home = os.path.expanduser('~')
def wait_load_items(driver, xpath):
n = 1
p = 1
while p:
try:
driver.find_element_by_xpath(xpath)
p = 0
except:
print(n, xpath)
time.sleep(1)
n += 1
if n == 300:
print('Tempo de espera excedito. Processo encerrado.')
exit()
def click_css_selector(driver, css_selector):
n = 0
p = 1
while p:
try:
driver.find_element_by_css_selector(css_selector).click()
p = 0
except:
time.sleep(1)
n += 1

	if n == 300:
		print('Tempo de espera excedido.')
		break

def download_hidroweb(id_station, name_estation, dir_out):
display = Display(visible=0, size=(800,600))
display.start()
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.folderList",2)
fp.set_preference("browser.download.dir",dir_out)
fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/msword, application/csv, application/ris, text/csv, image/png, application/pdf, text/html, text/plain, application/zip, application/x-zip, application/x-zip-compressed, application/download, application/octet-stream")
fp.set_preference("browser.download.manager.showWhenStarting", False)
fp.set_preference("browser.download.manager.focusWhenStarting", False)
fp.set_preference("browser.download.useDownloadDir", True)
fp.set_preference("browser.helperApps.alwaysAsk.force", False)
fp.set_preference("browser.download.manager.alertOnEXEOpen", False)
fp.set_preference("browser.download.manager.closeWhenDone", True)
fp.set_preference("browser.download.manager.showAlertOnComplete", False)
fp.set_preference("browser.download.manager.useWindow", False)
fp.set_preference("services.sync.prefs.sync.browser.download.manager.showWhenStarting", False)
fp.set_preference("pdfjs.disabled", True)
driver = webdriver.Firefox(firefox_profile=fp)
url = 'http://www.snirh.gov.br/hidroweb/publico/apresentacao.jsf'
driver.get(url)
time.sleep(1)
driver.get(url)
n = 0
p = 1
while p:
try:
driver.find_element_by_link_text('Séries Históricas').click()
p = 0
except:
time.sleep(1)
n += 1
if n == 300:
print('Tempo de espera excedido. Processo encerrado.')
exit()
wait_load_items(driver, '//[@id="form:fsListaEstacoes:codigoEstacao"]')
driver.find_element_by_xpath('//
[@id="form:fsListaEstacoes:codigoEstacao"]').send_keys([id_station, Keys.ENTER])
wait_load_items(driver, '//[@id="form:fsListaEstacoes:nomeEstacao"]')
driver.find_element_by_xpath('//
[@id="form:fsListaEstacoes:nomeEstacao"]').send_keys([name_estation, Keys.ENTER])
click_css_selector(driver, '#form\:fsListaEstacoes\:bt')
wait_load_items(driver, '//div[contains(@Class, "checkbox i-checks")]')
time.sleep(2)
try:
driver.find_element_by_xpath('//div[contains(@Class, "checkbox i-checks")]').click()
click_css_selector(driver, '#form\:fsListaEstacoes\:fsListaEstacoesC\:radTipoArquivo-componente > div:nth-child(2) > div:nth-child(2)')
click_css_selector(driver, '#form\:fsListaEstacoes\:fsListaEstacoesC\:btBaixar')
except Exception as e:
print(e)
ID_ESTACAO = '47001000'
NOME_ESTACAO = 'PORTO - TRAVESSIA DA BALSA'
download_hidroweb(ID_ESTACAO, NOME_ESTACAO, home)
`

@MichelCF
Copy link

MichelCF commented May 7, 2019

Estou trabalhando em uma nova versão do algoritimo
https://github.com/MichelCF/pyWidroweb

@caholar
Copy link

caholar commented May 13, 2019

Olá!
A nova versão do pyHidroweb rodou com sucesso no Python 3.7. Muito obrigada.!

@duartejr
Copy link

Nova versão do pyhidroweb.
https://github.com/duartejr/pyHidroWeb.git
Atualizada para a versão 3.0.6 do portal.
Agora também foi implementada uma nova funcionalidade para o cálculo de precipitação média usando o método de Thiessen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment