Módulo Tratadora

Expandir código fonte
import csv
import re


class Tratadora:
    """
    Limpe e exporte os dados climáticos de uma lista de cidades.

    Esta classe trata o contéudo HTML retornado pela classe Aranha e pode
    limpar e exportar os dados para CSV para plotagem pela classe Plotadora.

    :param campos: Cabeçalhos do arquivo CSV conforme os dados disponíveis
    """
    campos = ['Dia', 'Data', 'Máx', 'Min', 'Chuva']

    def extrair(self, lista_cidades):
        """
        Extraia os dados do HTML obtido e salve no objeto cidade.

        Este método utiliza os dados contidos no documento HTML para
        obter o nome completo da cidade e os dados meteorológicos para
        cada dia da semana em forma de tags HTML a partir dos seletores CSS.

        É preciso utilizar este método antes dos demais métodos da classe.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        # define um dicionário com os seletores css correspondentes a cada dado
        sel = {'previsao': 'previsao text-center',
               'estendida': 'proximos-dias text-centerc w-100',
               'final': 'previsao-estendida text-center w-100'}

        for c in lista_cidades:
            try:
                title = c.soup.title.text
                title = ' '.join(title.split())
                title = title.replace('Previsão de Tempo -', '').strip()
                title = title.replace('- Centro de Previsão de Tempo e '
                                      'Estudos Climáticos - INPE', '').strip()
                c.nome_extenso = title

                c.semana.append(c.soup.find_all('div', sel['previsao'])[0])
                c.semana.append(c.soup.find_all('div', sel['previsao'])[1])

                for e in c.soup.find_all('div', sel['estendida']):
                    c.semana.append(e)

                c.semana.append(c.soup.find_all('div', sel['final'])[4])
            except AttributeError:
                print(' [tratadora.extrair] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.extrair] ' + str(e))

    def exibir(self, lista_cidades):
        """
        Exiba os dados atuais de cada cidade no console.

        Funciona apenas após a utilização do método extrair.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        print()
        for c in lista_cidades:
            try:
                if not len(c.nome_extenso) == 0:
                    print(' [tratadora.exibir] ' + c.nome_extenso + ':')
                for d in c.semana:
                    print(str(d))
                print(c.meteograma + '\n')
            except AttributeError:
                print(' [tratadora.exibir] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.exibir] ' + str(e))

    def limpar(self, lista_cidades):
        """
        Remova caracteres desnecessários e ordene os dados.

        É preciso utilizar primeiro o método extrair para popular a
        propriedade semana de cada objeto da lista.

        A posição dos dados no HTML difere para os dois primeiros dias,
        (dia atual e seguinte), necessitando reordenar os dados.
        Os números nas listas ordem_inicio e ordem_fim correspondem
        à posição dos campos 'Dia', 'Data', 'Máx', 'Min' e 'Chuva' depois
        que as demais palavras são removidas.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        for c in lista_cidades:
            # remove palavras desnecessárias, deixando apenas os dados

            filtro = ['Índice UV [0-9]{2}', 'Prob. de Chuva', 'Temperatura',
                      '[0-9]{2}:[0-9]{2}', '-Feira', 'Manhã', 'Tarde', 'Noite',
                      '%', '°']
            try:
                for d, dia in enumerate(c.semana):
                    c.semana[d] = ' '.join(c.semana[d].text.split())
                    for f in filtro:
                        c.semana[d] = re.sub(f, '', c.semana[d])
                    c.semana[d] = ' '.join(c.semana[d].split())
            except AttributeError:
                print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.limpar] ' + str(e))

            # inicializa uma lista vazia que conterá um dia em cada posição
            linhas = []

            ordem_inicio = [0, 1, 3, 4, 2]  # dia atual e dia seguinte
            ordem_fim = [0, 1, 3, 2, 4]  # demais dias

            # varre os dados atuais da semana no objeto
            try:
                for d, dia in enumerate(c.semana):
                    dia_split = dia.split()
                    linha = []

                    # para o dia atual e dia seguinte
                    if d < 2:
                        # se há dados para manhã, tarde e noite,
                        # substituir os três valores pela média
                        if len(dia_split) == 7:
                            dia_split[2] = (float(dia_split[2]) + float(
                                dia_split[3]) + float(dia_split[4])) / 3
                            del dia_split[3:5]
                        # se há dados para tarde e noite, substituir pela média
                        elif len(dia_split) == 6:
                            dia_split[2] = (int(dia_split[2]) + int(
                                dia_split[3])) / 2
                            del dia_split[3]

                        # adiciona cada dado na ordem
                        for i in ordem_inicio:
                            linha.append(dia_split[i])

                    # para os demais dias, apenas adiciona na ordem
                    else:
                        for i in ordem_fim:
                            linha.append(dia_split[i])

                    # converte os dados numéricos para o tipo float
                    linha[2] = float(linha[2])
                    linha[3] = float(linha[3])
                    linha[4] = float(linha[4])

                    # adiciona os dados ao atributo semana do objeto
                    linhas.append(linha)
                    c.semana[d] = linha
            except AttributeError:
                print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.limpar] ' + str(e))

    def exportar(self, lista_cidades):
        """
        Crie um arquivo CSV com os dados limpos.

        Deve ser utilizado após os métodos extrair e limpar

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        for c in lista_cidades:
            try:
                saida_csv = open(c.saida_csv, 'w')
            except IOError:
                print(' [tratadora.exportar] Erro de entrada e saída')
            except Exception as e:
                print(' [tratadora.exportar] ' + str(e))
            else:
                with saida_csv:
                    try:
                        csv_writer = csv.writer(saida_csv)
                        csv_writer.writerow(self.campos)
                        print(' [tratadora.exportar] Pronta para gravar ' +
                              str(len(c.semana)) + ' linhas')
                    except AttributeError:
                        print(' [tratadora.exportar] AttributeError: O ' +
                              'arquivo HTML para ' + c.nome + ' foi baixado?')
                    except Exception as e:
                        print(' [tratadora.exportar] ' + str(e))
                    else:
                        for dia in c.semana:
                            csv_writer.writerow(dia)
                        print(' [tratadora.exportar] Dados exportados')

Classes

class Tratadora

Limpe e exporte os dados climáticos de uma lista de cidades.

Esta classe trata o contéudo HTML retornado pela classe Aranha e pode limpar e exportar os dados para CSV para plotagem pela classe Plotadora.

atributo campos
Cabeçalhos do arquivo CSV conforme os dados disponíveis
Expandir código fonte
class Tratadora:
    """
    Limpe e exporte os dados climáticos de uma lista de cidades.

    Esta classe trata o contéudo HTML retornado pela classe Aranha e pode
    limpar e exportar os dados para CSV para plotagem pela classe Plotadora.

    :param campos: Cabeçalhos do arquivo CSV conforme os dados disponíveis
    """
    campos = ['Dia', 'Data', 'Máx', 'Min', 'Chuva']

    def extrair(self, lista_cidades):
        """
        Extraia os dados do HTML obtido e salve no objeto cidade.

        Este método utiliza os dados contidos no documento HTML para
        obter o nome completo da cidade e os dados meteorológicos para
        cada dia da semana em forma de tags HTML a partir dos seletores CSS.

        É preciso utilizar este método antes dos demais métodos da classe.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        # define um dicionário com os seletores css correspondentes a cada dado
        sel = {'previsao': 'previsao text-center',
               'estendida': 'proximos-dias text-centerc w-100',
               'final': 'previsao-estendida text-center w-100'}

        for c in lista_cidades:
            try:
                title = c.soup.title.text
                title = ' '.join(title.split())
                title = title.replace('Previsão de Tempo -', '').strip()
                title = title.replace('- Centro de Previsão de Tempo e '
                                      'Estudos Climáticos - INPE', '').strip()
                c.nome_extenso = title

                c.semana.append(c.soup.find_all('div', sel['previsao'])[0])
                c.semana.append(c.soup.find_all('div', sel['previsao'])[1])

                for e in c.soup.find_all('div', sel['estendida']):
                    c.semana.append(e)

                c.semana.append(c.soup.find_all('div', sel['final'])[4])
            except AttributeError:
                print(' [tratadora.extrair] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.extrair] ' + str(e))

    def exibir(self, lista_cidades):
        """
        Exiba os dados atuais de cada cidade no console.

        Funciona apenas após a utilização do método extrair.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        print()
        for c in lista_cidades:
            try:
                if not len(c.nome_extenso) == 0:
                    print(' [tratadora.exibir] ' + c.nome_extenso + ':')
                for d in c.semana:
                    print(str(d))
                print(c.meteograma + '\n')
            except AttributeError:
                print(' [tratadora.exibir] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.exibir] ' + str(e))

    def limpar(self, lista_cidades):
        """
        Remova caracteres desnecessários e ordene os dados.

        É preciso utilizar primeiro o método extrair para popular a
        propriedade semana de cada objeto da lista.

        A posição dos dados no HTML difere para os dois primeiros dias,
        (dia atual e seguinte), necessitando reordenar os dados.
        Os números nas listas ordem_inicio e ordem_fim correspondem
        à posição dos campos 'Dia', 'Data', 'Máx', 'Min' e 'Chuva' depois
        que as demais palavras são removidas.

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        for c in lista_cidades:
            # remove palavras desnecessárias, deixando apenas os dados

            filtro = ['Índice UV [0-9]{2}', 'Prob. de Chuva', 'Temperatura',
                      '[0-9]{2}:[0-9]{2}', '-Feira', 'Manhã', 'Tarde', 'Noite',
                      '%', '°']
            try:
                for d, dia in enumerate(c.semana):
                    c.semana[d] = ' '.join(c.semana[d].text.split())
                    for f in filtro:
                        c.semana[d] = re.sub(f, '', c.semana[d])
                    c.semana[d] = ' '.join(c.semana[d].split())
            except AttributeError:
                print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.limpar] ' + str(e))

            # inicializa uma lista vazia que conterá um dia em cada posição
            linhas = []

            ordem_inicio = [0, 1, 3, 4, 2]  # dia atual e dia seguinte
            ordem_fim = [0, 1, 3, 2, 4]  # demais dias

            # varre os dados atuais da semana no objeto
            try:
                for d, dia in enumerate(c.semana):
                    dia_split = dia.split()
                    linha = []

                    # para o dia atual e dia seguinte
                    if d < 2:
                        # se há dados para manhã, tarde e noite,
                        # substituir os três valores pela média
                        if len(dia_split) == 7:
                            dia_split[2] = (float(dia_split[2]) + float(
                                dia_split[3]) + float(dia_split[4])) / 3
                            del dia_split[3:5]
                        # se há dados para tarde e noite, substituir pela média
                        elif len(dia_split) == 6:
                            dia_split[2] = (int(dia_split[2]) + int(
                                dia_split[3])) / 2
                            del dia_split[3]

                        # adiciona cada dado na ordem
                        for i in ordem_inicio:
                            linha.append(dia_split[i])

                    # para os demais dias, apenas adiciona na ordem
                    else:
                        for i in ordem_fim:
                            linha.append(dia_split[i])

                    # converte os dados numéricos para o tipo float
                    linha[2] = float(linha[2])
                    linha[3] = float(linha[3])
                    linha[4] = float(linha[4])

                    # adiciona os dados ao atributo semana do objeto
                    linhas.append(linha)
                    c.semana[d] = linha
            except AttributeError:
                print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                      'para ' + c.nome + ' foi baixado?')
            except Exception as e:
                print(' [tratadora.limpar] ' + str(e))

    def exportar(self, lista_cidades):
        """
        Crie um arquivo CSV com os dados limpos.

        Deve ser utilizado após os métodos extrair e limpar

        :param lista_cidades: Lista de objetos da classe Cidade
        """

        for c in lista_cidades:
            try:
                saida_csv = open(c.saida_csv, 'w')
            except IOError:
                print(' [tratadora.exportar] Erro de entrada e saída')
            except Exception as e:
                print(' [tratadora.exportar] ' + str(e))
            else:
                with saida_csv:
                    try:
                        csv_writer = csv.writer(saida_csv)
                        csv_writer.writerow(self.campos)
                        print(' [tratadora.exportar] Pronta para gravar ' +
                              str(len(c.semana)) + ' linhas')
                    except AttributeError:
                        print(' [tratadora.exportar] AttributeError: O ' +
                              'arquivo HTML para ' + c.nome + ' foi baixado?')
                    except Exception as e:
                        print(' [tratadora.exportar] ' + str(e))
                    else:
                        for dia in c.semana:
                            csv_writer.writerow(dia)
                        print(' [tratadora.exportar] Dados exportados')

Métodos

def exibir(self, lista_cidades)

Exiba os dados atuais de cada cidade no console.

Funciona apenas após a utilização do método extrair.

parâmetro lista_cidades
lista com objetos da classe Cidade
Expandir código fonte
def exibir(self, lista_cidades):
    """
    Exiba os dados atuais de cada cidade no console.

    Funciona apenas após a utilização do método extrair.

    :param lista_cidades: Lista de objetos da classe Cidade
    """

    print()
    for c in lista_cidades:
        try:
            if not len(c.nome_extenso) == 0:
                print(' [tratadora.exibir] ' + c.nome_extenso + ':')
            for d in c.semana:
                print(str(d))
            print(c.meteograma + '\n')
        except AttributeError:
            print(' [tratadora.exibir] AttributeError: O arquivo HTML ' +
                  'para ' + c.nome + ' foi baixado?')
        except Exception as e:
            print(' [tratadora.exibir] ' + str(e))
def exportar(self, lista_cidades)

Crie um arquivo CSV com os dados limpos.

Deve ser utilizado após os métodos extrair e limpar

parâmetro lista_cidades
lista com objetos da classe Cidade
Expandir código fonte
def exportar(self, lista_cidades):
    """
    Crie um arquivo CSV com os dados limpos.

    Deve ser utilizado após os métodos extrair e limpar

    :param lista_cidades: Lista de objetos da classe Cidade
    """

    for c in lista_cidades:
        try:
            saida_csv = open(c.saida_csv, 'w')
        except IOError:
            print(' [tratadora.exportar] Erro de entrada e saída')
        except Exception as e:
            print(' [tratadora.exportar] ' + str(e))
        else:
            with saida_csv:
                try:
                    csv_writer = csv.writer(saida_csv)
                    csv_writer.writerow(self.campos)
                    print(' [tratadora.exportar] Pronta para gravar ' +
                          str(len(c.semana)) + ' linhas')
                except AttributeError:
                    print(' [tratadora.exportar] AttributeError: O ' +
                          'arquivo HTML para ' + c.nome + ' foi baixado?')
                except Exception as e:
                    print(' [tratadora.exportar] ' + str(e))
                else:
                    for dia in c.semana:
                        csv_writer.writerow(dia)
                    print(' [tratadora.exportar] Dados exportados')
def extrair(self, lista_cidades)

Extraia os dados do HTML obtido e salve no objeto cidade.

Este método utiliza os dados contidos no documento HTML para obter o nome completo da cidade e os dados meteorológicos para cada dia da semana em forma de tags HTML a partir dos seletores CSS.

É preciso utilizar este método antes dos demais métodos da classe.

parâmetro lista_cidades
lista com objetos da classe Cidade
Expandir código fonte
def extrair(self, lista_cidades):
    """
    Extraia os dados do HTML obtido e salve no objeto cidade.

    Este método utiliza os dados contidos no documento HTML para
    obter o nome completo da cidade e os dados meteorológicos para
    cada dia da semana em forma de tags HTML a partir dos seletores CSS.

    É preciso utilizar este método antes dos demais métodos da classe.

    :param lista_cidades: Lista de objetos da classe Cidade
    """

    # define um dicionário com os seletores css correspondentes a cada dado
    sel = {'previsao': 'previsao text-center',
           'estendida': 'proximos-dias text-centerc w-100',
           'final': 'previsao-estendida text-center w-100'}

    for c in lista_cidades:
        try:
            title = c.soup.title.text
            title = ' '.join(title.split())
            title = title.replace('Previsão de Tempo -', '').strip()
            title = title.replace('- Centro de Previsão de Tempo e '
                                  'Estudos Climáticos - INPE', '').strip()
            c.nome_extenso = title

            c.semana.append(c.soup.find_all('div', sel['previsao'])[0])
            c.semana.append(c.soup.find_all('div', sel['previsao'])[1])

            for e in c.soup.find_all('div', sel['estendida']):
                c.semana.append(e)

            c.semana.append(c.soup.find_all('div', sel['final'])[4])
        except AttributeError:
            print(' [tratadora.extrair] AttributeError: O arquivo HTML ' +
                  'para ' + c.nome + ' foi baixado?')
        except Exception as e:
            print(' [tratadora.extrair] ' + str(e))
def limpar(self, lista_cidades)

Remova caracteres desnecessários e ordene os dados.

É preciso utilizar primeiro o método extrair para popular a propriedade semana de cada objeto da lista.

parâmetro lista_cidades
lista com objetos da classe Cidade
Expandir código fonte
def limpar(self, lista_cidades):
    """
    Remova caracteres desnecessários e ordene os dados.

    É preciso utilizar primeiro o método extrair para popular a
    propriedade semana de cada objeto da lista.

    A posição dos dados no HTML difere para os dois primeiros dias,
    (dia atual e seguinte), necessitando reordenar os dados.
    Os números nas listas ordem_inicio e ordem_fim correspondem
    à posição dos campos 'Dia', 'Data', 'Máx', 'Min' e 'Chuva' depois
    que as demais palavras são removidas.

    :param lista_cidades: Lista de objetos da classe Cidade
    """

    for c in lista_cidades:
        # remove palavras desnecessárias, deixando apenas os dados

        filtro = ['Índice UV [0-9]{2}', 'Prob. de Chuva', 'Temperatura',
                  '[0-9]{2}:[0-9]{2}', '-Feira', 'Manhã', 'Tarde', 'Noite',
                  '%', '°']
        try:
            for d, dia in enumerate(c.semana):
                c.semana[d] = ' '.join(c.semana[d].text.split())
                for f in filtro:
                    c.semana[d] = re.sub(f, '', c.semana[d])
                c.semana[d] = ' '.join(c.semana[d].split())
        except AttributeError:
            print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                  'para ' + c.nome + ' foi baixado?')
        except Exception as e:
            print(' [tratadora.limpar] ' + str(e))

        # inicializa uma lista vazia que conterá um dia em cada posição
        linhas = []

        ordem_inicio = [0, 1, 3, 4, 2]  # dia atual e dia seguinte
        ordem_fim = [0, 1, 3, 2, 4]  # demais dias

        # varre os dados atuais da semana no objeto
        try:
            for d, dia in enumerate(c.semana):
                dia_split = dia.split()
                linha = []

                # para o dia atual e dia seguinte
                if d < 2:
                    # se há dados para manhã, tarde e noite,
                    # substituir os três valores pela média
                    if len(dia_split) == 7:
                        dia_split[2] = (float(dia_split[2]) + float(
                            dia_split[3]) + float(dia_split[4])) / 3
                        del dia_split[3:5]
                    # se há dados para tarde e noite, substituir pela média
                    elif len(dia_split) == 6:
                        dia_split[2] = (int(dia_split[2]) + int(
                            dia_split[3])) / 2
                        del dia_split[3]

                    # adiciona cada dado na ordem
                    for i in ordem_inicio:
                        linha.append(dia_split[i])

                # para os demais dias, apenas adiciona na ordem
                else:
                    for i in ordem_fim:
                        linha.append(dia_split[i])

                # converte os dados numéricos para o tipo float
                linha[2] = float(linha[2])
                linha[3] = float(linha[3])
                linha[4] = float(linha[4])

                # adiciona os dados ao atributo semana do objeto
                linhas.append(linha)
                c.semana[d] = linha
        except AttributeError:
            print(' [tratadora.limpar] AttributeError: O arquivo HTML ' +
                  'para ' + c.nome + ' foi baixado?')
        except Exception as e:
            print(' [tratadora.limpar] ' + str(e))