Search
Close this search box.
Python app fácil para previsão do tempo com dados do INPE
aprendiz artificial

Posts Relacionados:

Nesse post, nós mostraremos como criar um Python app para previsão do tempo para os próximos dias utilizando dados dinâmicos do INPE.

Receba nossa newsletter

O Python é uma linguagem muito versátil. Nesse post, iremos usá-lo para acessar o site do Instituto Nacional de Pesquisas Espaciais (INPE). Nosso objetivo é criar um pequeno Python app para previsão do tempo que aceita uma cidade como entrada e retorna a previsão para os próximos dias.

Esse aplicativo será usado num post futuro para a criação de um chatbot baseado em regras.

Requerimentos

Bibliotecas:

  1. lxml – para manipular arquivos XML
  2. requests – para acessar URLs com Python
  3. unidecode – para remover acentuações de palavras

Para instalações com pip:

				
					pip install lxml
pip install requests
pip install Unidecode
				
			

Para instalações com o Anaconda:

				
					conda install -c anaconda lxml
conda install -c anaconda requests
conda install -c conda-forge unidecode
				
			

Módulo que será usado:

  1. pprint – para imprimir os resultados obtidos de forma mais legível

Objetivos - criar um Python app para previsão do tempo

O INPE disponibiliza dados com previsões do tempo para todo o Brasil em XML. A requisição desses dados é feita via uma URL que, na maioria das vezes, deve ter o código da localidade desejada inserida em seu conteúdo. Portanto, temos dois objetivos:

  • Obter o código numérico correspondente para cada localidade informada por um usuário do nosso aplicativo.
  • Usar esse código para obter a previsão do tempo para os próximos dias.
aprendiz artificial

Descrição geral dos procedimentos

Iremos criar duas funções para acessar os dados do INPE.

A primeira função tem como argumento o nome de uma cidade fornecida por um usuário do programa. Esse nome precisa ser inserido dinamicamente na URL do INPE.

Se o acesso ao site do INPE for bem-sucedido, nossa primeira função retornará o código numérico da cidade. Ele será o argumento de uma segunda função.

O objetivo da segunda função é acessar outra página do INPE para obter a previsão do tempo.

Importação das bibliotecas e módulo

Para começar, vamos fazer as importações necessárias.

				
					from lxml import etree
import pprint
import requests
from unidecode import unidecode
				
			

Criação da primeira função

Nossa primeira função (busca_codigo) tem como argumento o nome de uma cidade do território brasileiro. Ele será usado para completar dinamicamente a URL do INPE que precisamos acessar.

É preciso converter todas as letras do nome para minúsculas com o comando lower (linha 2). Adicionalmente, é necessário remover qualquer acentuação que o nome fornecido possa ter com o comando unidecode (linha 3). Em seguida, usamos o comando requests.get() (linha 5) para acessar a URL como no código abaixo:

				
					  
def busca_codigo(cidade):
    cidade = cidade.lower()
    cidade = unidecode(cidade)
    url = f"http://servicos.cptec.inpe.br/XML/listaCidades?city={cidade}"
    response = requests.get(url)


				
			

Para verificar se o acesso foi bem-sucedido, é fundamental confirmar o status da resposta HTTP como 200 (linha 6 no código abaixo).

th-1637988978

Status HTTP retirados daqui.

Nessa etapa, também é importante criar uma mensagem para informar ao usuário do app quando houver uma falha no acesso (linhas 8 e 9). Veja o código abaixo.

				
					
def busca_codigo(cidade):
    cidade = cidade.lower()
    cidade = unidecode(cidade)
    url = f"http://servicos.cptec.inpe.br/XML/listaCidades?city={cidade}"
    response = requests.get(url)
    if response.status_code == 200: 
        print('sucesso')
    else: 
        return "Houve um problema com sua solicitação. Por favor, confira e digite novamente."

				
			

Vamos testar se nossa função está correta até aqui verificando o acesso para a cidade de São Paulo. Digite o código abaixo fora da função, salve e execute o arquivo.

				
					
cidade = 'São Paulo'
nome_id = busca_codigo(cidade)
    


				
			

O resultado obtido deve ser a palavra sucesso escrita diretamente no terminal.

Obtendo o arquivo XML

Em seguida, é preciso pegar o conteúdo da página do INPE em XML (linha 4 abaixo).

				
					
def busca_codigo(cidade):
    ...
    if response.status_code == 200: 
        xml_data = response.content
        print(xml_data)

    ...

				
			

Executando esse código, nós obtemos uma resposta XML como a mostrada abaixo. Para extrair o conteúdo necessário (id) do arquivo XML, utilizaremos a biblioteca lxml.

				
					b"<?xml version='1.0' encoding='ISO-8859-1'?><cidades><cidade><nome>S\xe3o Paulo</nome><uf>SP</uf><id>244</id></cidade><cidade><nome>S\xe3o Paulo das Miss\xf5es</nome><uf>RS</uf><id>5019</id></cidade><cidade><nome>S\xe3o Paulo de Oliven\xe7a</nome><uf>AM</uf><id>5020</id></cidade><cidade><nome>S\xe3o Paulo do Potengi</nome><uf>RN</uf><id>5021</id></cidade></cidades>"
    


				
			

A funcionalidade etree da biblioteca lxml será usada para converter o conteúdo XML num elemento de mais fácil inspeção (linha 5). Essa conversão possibilita usar os termos presentes no XML (por exemplo, nome, id) para buscar diretamente o texto correspondente de cada um. Digite a linha 5 abaixo em seu código:

				
					
def busca_codigo(cidade):
    ...
    if response.status_code == 200: 
        xml_data = response.content
        texto = etree.fromstring(xml_data) 
  
    ...

				
			

Extração do código numérico

Por fim, é preciso garantir que o conteúdo da resposta obtida tem o código numérico desejado. Em caso de erro, a URL do INPE retorna None. Portanto, é fundamental confirmar que nosso conteúdo é mesmo o código da localidade usando uma estrutura condicional (linhas 4-8 abaixo). Se o resultado for correto (linhas 6-8 abaixo), a função extrairá o id utilizando o elemento texto criado com a funcionalidade etree (linha 7).

				
					
def busca_codigo(cidade):
    ...
        texto = etree.fromstring(xml_data) 
        if texto.find('cidade') == None: 
            return "Houve um problema com sua solicitação. Por favor, confira e digite novamente."
        else: 
            nome_id = int(texto.find('cidade').find('id').text)
            return nome_id
    ...

				
			

Testando a primeira função

Nossa primeira função está terminada. Vamos executar o código e testar uma nova cidade. O código da função completa com seu chamado é mostrado abaixo.

				
					
def busca_codigo(cidade):
    cidade = cidade.lower()
    cidade = unidecode(cidade)
    url = f"http://servicos.cptec.inpe.br/XML/listaCidades?city={cidade}"
    response = requests.get(url)
    if response.status_code == 200: 
        xml_data = response.content 
        texto = etree.fromstring(xml_data) 
        if texto.find('cidade') == None: 
            return 'Houve um problema com sua solicitação. Por favor, confira e digite novamente.' 
        else: 
            nome_id = int(texto.find('cidade').find('id').text) 
            return nome_id
    else: 
        return 'Houve um problema com sua solicitação. Por favor, confira e digite novamente.'

cidade = 'Manaus'
nome_id = busca_codigo(cidade)
print(nome_id)

				
			

Se seu código estiver correto, você deverá ver o número 234 impresso no terminal.

Verificando o retorno correto

A segunda função (busca_clima) que será criada tem como argumento o código numérico (nome_id) obtido anteriormente.

Porém, antes de chamá-la, é necessário garantir novamente que o código numérico foi retornado com sucesso. Para isso, a segunda função precisa ser chamada apenas numa estrutura condicional que verifica se o código numérico é do tipo int. Se essa condicional falhar, como no exemplo abaixo (linha 4), o código não foi localizado e o usuário da aplicação receberá uma mensagem indicando o erro.

				
					
def busca_clima(nome_id):
    pass

cidade = 'Rio de Janeio'
nome_id = busca_codigo(cidade)

if type(nome_id)==int:
    busca_clima(nome_id)

else:
    print(nome_id)

				
			

Resultado em caso de erro no nome da cidade.

				
					
Houve um problema com sua solicitação. Por favor, confira e digite novamente.
				
			

A segunda função

A estrutura da segunda função é bastante parecida à função anterior. Ela inicia com o acesso à URL da previsão do tempo usando o código numérico (nome_id) como argumento dinâmico. É preciso verificar com uma estrutura condicional se o status do acesso é 200. Em caso de erro, ela retornará uma mensagem acusando a falha. Digite e execute o código abaixo. Sua execução deve escrever a palavra sucesso no terminal.

				
					
def busca_clima(nome_id):
    url = f"http://servicos.cptec.inpe.br/XML/cidade/7dias/{nome_id}/previsao.xml"
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        print("sucesso")
    else: 
        print('Houve um problema com a sua solicitação. Por favor, confira e digite novamente.')
     
cidade = 'Rio de Janeiro'
nome_id = busca_codigo(cidade)

if type(nome_id)==int:
    busca_clima(nome_id)
else:
    print(nome_id)
				
			

Na sequência, o conteúdo da página é obtido e convertido em elemento para inspeção pela funcionalidade etree.

				
					
def busca_clima(nome_id):
    ...
    if response.status_code == 200:
        xml_data = response.content 
        root = etree.fromstring(xml_data)
   ...
				
			

Abaixo, veja um exemplo de arquivo XML que o INPE retorna com a previsão completa para a localidade buscada. É esse tipo de arquivo que a funcionalidade etree facilita a inspeção. Ela é capaz de extrair diretamente o texto de cada elemento do arquivo.

				
					b"<?xml version='1.0' encoding='ISO-8859-1'?><cidade><nome>S\xe3o Paulo</nome><uf>SP</uf><atualizacao>2023-10-08</atualizacao><previsao><dia>2023-10-09</dia><tempo>c</tempo><maxima>26</maxima><minima>19</minima><iuv>12.0</iuv></previsao><previsao><dia>2023-10-10</dia><tempo>pn</tempo><maxima>21</maxima><minima>16</minima><iuv>12.0</iuv></previsao><previsao><dia>2023-10-11</dia><tempo>pn</tempo><maxima>32</maxima><minima>16</minima><iuv>12.0</iuv></previsao><previsao><dia>2023-10-12</dia><tempo>pn</tempo><maxima>32</maxima><minima>21</minima><iuv>12.0</iuv></previsao><previsao><dia>2023-10-13</dia><tempo>pn</tempo><maxima>25</maxima><minima>17</minima><iuv>12.0</iuv></previsao><previsao><dia>2023-10-14</dia><tempo>pn</tempo><maxima>20</maxima><minima>15</minima><iuv>12.0</iuv></previsao></cidade>"
				
			

Os dados do INPE

O INPE informa que, para cada localidade, fornece a previsão para os próximos 7 dias, mas nossos arquivos retornaram dados para apenas 6 dias.

Para cada dia, a previsão do INPE tem um código descritivo do clima (por exemplo, a letra c significa chuva), a temperatura mínima e a máxima e o índice UV.

Iremos utilizar um loop para salvar todos esses dados num dicionário. Adicionalmente, para tornar nosso arquivo compreensível para um usuário, nossa função irá converter o código da previsão do INPE (tempo na função busca_clima) usando um dicionário com a descrição correspondente. O dicionário é mostrado abaixo. Para usá-lo, é necessário copiá-lo e importá-lo no arquivo do seu código (adicione no início do código a linha: from clima_codigos import clima_dic).

				
					
clima_dic = {
"ec": "Encoberto com Chuvas Isoladas",
"ci": "Chuvas Isoladas",
"c":  "Chuva",
"in": "Instável",
"pp": "Possilidade de Pancadas de Chuva",
"cm": "Chuva pela Manhã",
"cn": "Chuva a Noite",
"pt": "Pancadas de Chuva a Tarde",
"pm": "Pancadas de Chuva pela Manhã",
"np": "Nublado e Pancadas de Chuva",
"pc": "Pancadas de Chuva",
"pn": "Parcialmente Nublado",
"cv": "Chuvisco",
"ch": "Chuvoso",
"t": "Tempestade",
"ps": "Predomínio de Sol",
"e": "Encoberto",
"n": "Nublado",
"cl": "Céu Claro",
"nv": "Nevoeiro",
"g": "Geada",
"ne": "Neve",
"nd": "Não Definido",
"pnt": "Pancadas de Chuva a Noite",
"psc": "Possibilidade de Chuva",
"pcm": "Possibilidade de Chuva pela Manhã",
"pct": "Possibilidade de Chuva a Tarde",
"pcn": "Possibilidade de Chuva a Noite",
"npt": "Nublado com Pancadas a Tarde",
"npn": "Nublado com Pancadas a Noite",
"ncn": "Nublado com Poss. de Chuva a Noite",
"nct": "Nublado com Poss. de Chuva a Tarde",
"ncm": "Nublado com Poss. de Chuva pela Manhã",
"npm": "Nublado com Pancadas pela Manhã",
"npp": "Nublado com Possibilidade de Chuva",
"vn": "Variação de Nebulosidade",
"ct": "Chuva a Tarde",
"ppn": "Poss. de Panc. de Chuva a Noite",
"ppt": "Poss. de Panc. de Chuva a Tarde",
"ppm": "Poss. de Panc. de Chuva pela Manhã"}


				
			

Para salvar todas as informações do INPE de maneira organizada, utilizaremos um contador para enumerar cada dia da previsão com seus dados correspondentes (linha 7 e linha 14). Após o término do loop, o dicionário é impresso com o auxílio do comando pprint para torná-lo mais legível.

				
					
def busca_clima(nome_id):
   ...
        root = etree.fromstring(xml_data)
        dados = {}
        contador = 0
        for previsao in root.findall('previsao'):
            contador += 1
            dia = (previsao.find('dia').text)
            tempo = (previsao.find('tempo').text)
            prev = clima_dic[tempo]
            Tmax = (previsao.find('maxima').text)
            Tmin = (previsao.find('minima').text)
            iuv = (previsao.find('iuv').text)
            dados['dia '+str(contador)] = (dia, prev, Tmax, Tmin, iuv)
        pprint.pprint(dados)
   ...
				
			

Pronto! Agora é só salvar tudo e testar com várias cidades diferentes. O código completo da segunda função é mostrado abaixo.

				
					

def busca_clima(nome_id):
    url = f"http://servicos.cptec.inpe.br/XML/cidade/7dias/{nome_id}/previsao.xml"
    response = requests.get(url, stream=True)
    if response.status_code == 200:
        xml_data = response.content 
        root = etree.fromstring(xml_data)
        dados = {}
        contador = 0
        for previsao in root.findall('previsao'):
            contador += 1
            dia = (previsao.find('dia').text)
            tempo = (previsao.find('tempo').text)
            prev = clima_dic[tempo]
            Tmax = (previsao.find('maxima').text)
            Tmin = (previsao.find('minima').text)
            iuv = (previsao.find('iuv').text)
            dados['dia '+str(contador)] = (dia, prev, Tmax, Tmin, iuv)
        pprint.pprint(dados)
    else: 
        print('Houve um problema com a sua solicitação. Por favor, confira e digite novamente.')
        
cidade = 'Rio de Janeiro'
nome_id = busca_codigo(cidade)
if type(nome_id)==int:
    busca_clima(nome_id)
else:
    print(nome_id)
     
				
			

Veja um exemplo de previsão obtida para o Rio de janeiro.

				
					

{'dia 1': ('2023-10-08', 'Chuva', '29', '24', '11.0'),
 'dia 2': ('2023-10-09', 'Parcialmente Nublado', '29', '23', '11.0'),
 'dia 3': ('2023-10-10', 'Parcialmente Nublado', '27', '22', '12.0'),
 'dia 4': ('2023-10-11', 'Parcialmente Nublado', '30', '22', '12.0'),
 'dia 5': ('2023-10-12', 'Parcialmente Nublado', '32', '23', '11.0'),
 'dia 6': ('2023-10-13', 'Parcialmente Nublado', '24', '22', '11.0')}
				
			

Conclusão

Nesse post, usamos o Python para criar um pequeno aplicativo para previsão do tempo com dados obtidos dinamicamente do site do INPE. Para quem tiver interesse, o INPE tem outros arquivos XML disponíveis e esse código pode ser facilmente modificado para retornar outros dados.

Imagem com IA Generativa – Dia 274

IA generativa img 274

Arte com IA generativa: imagem do dia

Todos os dias, postamos um exemplo de imagem artística gerada com inteligência artificial.

Tutoriais

Postagens Mais Recentes

Outras Postagens Que Podem Interessar

Veja
Mais

Fique em contato

Se inscreva para receber nossa newsletter com novidades.

aprendiz artificial