Árvore

Domingo, 12 de julho de 2020

Atenção: Esta tarefa também será corrigida manualmente. Depois de terminada e corrigida automaticamente, você deve apresentar sua tarefa a um monitor em algum horário de atendimento. Você poderá pedir recorreção, mas o conceito da recorreção será no máximo B.

Árvore

Uma página HTML pode conter links para outras páginas. Queremos entender a hierarquia entre elas se começarmos a visitar um website a partir de uma determinada página. Faça um programa que recebe o link de uma página inicial e mostra a hierarquia entre as páginas que podem ser alcançadas a partir da inicial.

Dizemos que essa hierarquia forma uma árvore em que cada nó corresponde a uma página distinta. A raiz da árvore é a página inicial. Os filhos de um nó da árvore são as páginas HTML que são acessíveis a partir daquele nó. Por exemplo, se começássemos a navegar a partir de http://exemplo.com/index.html, poderíamos criar uma árvore como a seguinte.

Visitamos os links na ordem em que os encontramos nas páginas. Assim, ao visitar a página raiz, encontrarmos um link para o índice do blog, onde encontramos um link para o primeiro post e assim por diante. Repare que uma página pode ser acessada através de várias outras páginas, mas ela aparecerá na árvore apenas uma vez. Por exemplo, o índice do blog pode conter um link para o segundo post, mas como já tínhamos visto esse link antes, não o visitamos de novo.

Analisando uma página

Para descobrir os links, você deve analisar o conteúdo de cada página visitada e listar os links que ela possui. Uma página HTML nada mais é do que um arquivo de texto escrito em uma linguagem de marcação de estrutura e formato.

O arquivo é formado por uma sequência de tags balanceadas. Para descobrir os links, basta que você conheça o formato das tags de links. A seguir, há um exemplo de um link que você estará procurando.

<a href="https://ic.unicamp.br/graduacao/engenharia-da-computacao/">
  Engenharia da Computação
</a>

Essa tag define um link com o texto Engenharia da Computação que, se clicado, vai para a URL escrita. A parte que interessa é a propriedade href. Fazer uma análise completa de um arquivo HTML que funcione para qualquer página da internet não é uma tarefa trivial, mas, algumas vezes, simplificações são suficientes para o que queremos.

Nesta tarefa, você deve supor que todo link corresponde a uma substring com a forma href="[URL DA PÁGINA]", então basta procurar por substrings com esse formato e extrair URL entre as aspas duplas.

Não é difícil escrever um algoritmo para encontrar expressões como essa em uma string. Encontrar um padrão em uma string é uma tarefa tão comum que existe uma ferramenta especializada para ajudar: as expressões regulares. Se você preferir, poderá utilizá-las para encontrar os links presentes na página

Uma expressão regular é uma sequência de símbolos que representa um determinado padrão. Cada símbolo tem um significado especial. Abaixo, temos um exemplo de uma expressão regular que corresponde a um número telefônico. O padrão é definido como dois números entre parênteses seguidos de quatro ou cinco números, um traço e mais quatro números. Podemos utilizar o módulo re para definir e utilizar expressões regulares em Python.

>>> import re
>>> regex = r"\(\d{2}\) \d{4,5}-\d{4}"
>>> texto = "Esse é o meu número (00) 12345-6789"
>>> texto = "Ligue para (00) 2345-6789 ou para (01) 12345-4321"
>>> telefones = re.findall(regex, texto)
>>> telefones
['(00) 2345-6789', '(19) 12345-4321']

Neste link você pode encontrar vários exemplos interativos de como definir e utilizar expressões regulares. Entender como as expressões regulares mais sofisticadas funcionam é um assunto complicado que você só aprenderá ao estudar compiladores, mas aprender a usar os padrões mais simples pode ser útil. Não gaste muito tempo tentando aprender tudo.

Módulo auxiliar

No diretório, você encontrará um arquivo auxiliar modulo.py com várias funções já prontas para facilitar o desenvolvimento da tarefa. Há funções para para normalizar o formato das URLs, verificar se as URLs encontradas são válidas e para carregar páginas HTML. Essas funções ajudam nas tarefas descritas a seguir.

Resolvendo URLs

Ao visitar uma página, podemos encontrar endereços relativos ao diretório atual. Por exemplo, na página

https://ic.unicamp.br/~lehilton/mc102qr/unidades/10-eficiencia.html

encontramos um link para

../fixacao/07-ordenacao.html#exercicios-criativos

Nesse caso, a URL do link deve ser resolvida para

https://ic.unicamp.br/~lehilton/mc102qr/fixacao/07-ordenacao.html

Controlando o tamanho da árvore

Se visitarmos todos os links que encontrarmos, pode acontecer de visitarmos milhões de páginas. Para evitar que isso aconteça, vamos restringir os links de interesse.

Primeiro, não queremos visitar links para imagens, documentos PDF ou outros objetos. Assim, só visitaremos URLs que:

  1. ou terminem com /, i.e., correspondem ao índice de um diretório;
  2. ou terminem com extensão .htm ou .html, i.e., são arquivos HTML.

Além disso, só visitaremos páginas que estejam no mesmo diretório ou em subdiretórios da página inicial. Por exemplo, se a página inicial é

https://ic.unicamp.br/~lehilton/mc102qr/unidades/11-recursao.html

podemos visitar

https://ic.unicamp.br/~lehilton/mc102qr/unidades/10-eficiencia.html

mas não iremos visitar

https://ic.unicamp.br/~lehilton/mc102qr/fixacao/11-eficiencia.html

tampouco visitaremos

https://www.youtube.com/channel/UC81VD6eeuLLSfyY_D-N8sVw

mesmo que esses links apareçam no código HTML.

Baixando arquivos HTML

Há uma função no módulo que recebe uma URL e baixa o arquivo HTML em um diretório de cache. Por exemplo, se você encontrar o link

https://ic.unicamp.br/~lehilton/mc102qr/index.html

então a função baixará esse arquivo da Web e o guardará em um arquivo dentro do diretório local chamado

cache/ic.unicamp.br/~lehilton/mc102qr/index.html

A função devolverá uma string com todo o conteúdo do arquivo local se conseguir baixar, ou devolverá None se não tiver sido possível baixar ou se o conteúdo baixado não for um arquivo HTML.

Para os casos de teste desta tarefa, você já receberá uma cópia de páginas do site ic.unicamp.br junto do seu repositório, assim não é necessário estar conectado à internet enquanto estiver testando. Não altere, nem atualize esses arquivos. Se desejar testar com outras páginas, então você deve ter o módulo requests instalado.

Entrada e saída

Você deve criar um programa chamado arvore.py.

Entrada

Uma linha com a URL correspondente à página inicial.

https://ic.unicamp.br/~lehilton/mc102qr/index.html

Saída

Seu programa irá mostrar a árvore. Cada subnível da hierarquia é distinguido com um nível de recuo, utilizando 2 espaços.

https://ic.unicamp.br/~lehilton/mc102qr/index.html
  https://ic.unicamp.br/~lehilton/mc102qr/apresentacao.html
  https://ic.unicamp.br/~lehilton/mc102qr/fixacao.html
    https://ic.unicamp.br/~lehilton/mc102qr/fixacao/00-algoritmo.html
      https://ic.unicamp.br/~lehilton/mc102qr/fixacao/01-variaveis.html
        https://ic.unicamp.br/~lehilton/mc102qr/fixacao/02-condicional.html
          https://ic.unicamp.br/~lehilton/mc102qr/fixacao/03-repeticao.html
            https://ic.unicamp.br/~lehilton/mc102qr/fixacao/04-funcoes.html
              https://ic.unicamp.br/~lehilton/mc102qr/fixacao/05-praticas.html
                https://ic.unicamp.br/~lehilton/mc102qr/fixacao/06-listas.html
                  https://ic.unicamp.br/~lehilton/mc102qr/fixacao/07-ordenacao.html
                    https://ic.unicamp.br/~lehilton/mc102qr/fixacao/08-matrizes.html
                      https://ic.unicamp.br/~lehilton/mc102qr/fixacao/09-arquivos.html
                        https://ic.unicamp.br/~lehilton/mc102qr/fixacao/10-colecoes.html
                          https://ic.unicamp.br/~lehilton/mc102qr/fixacao/11-eficiencia.html
                            https://ic.unicamp.br/~lehilton/mc102qr/fixacao/12-recursao.html
  https://ic.unicamp.br/~lehilton/mc102qr/unidades/01-problemas-algoritmos.html
    https://ic.unicamp.br/~lehilton/mc102qr/unidades/02-escrevendo-algoritmos.html
      https://ic.unicamp.br/~lehilton/mc102qr/unidades/03-linguagens-programacao.html
        https://ic.unicamp.br/~lehilton/mc102qr/unidades/04-estruturas-elementares.html
          https://ic.unicamp.br/~lehilton/mc102qr/unidades/05-listas.html
            https://ic.unicamp.br/~lehilton/mc102qr/unidades/06-funcoes.html
              https://ic.unicamp.br/~lehilton/mc102qr/unidades/07-algortimos-iterativos.html
                https://ic.unicamp.br/~lehilton/mc102qr/unidades/08-matrizes.html
                  https://ic.unicamp.br/~lehilton/mc102qr/unidades/09-colecoes.html
                    https://ic.unicamp.br/~lehilton/mc102qr/unidades/10-eficiencia.html
                      https://ic.unicamp.br/~lehilton/mc102qr/unidades/11-recursao.html
                        https://ic.unicamp.br/~lehilton/mc102qr/tarefas/14-recursao.html
                          https://ic.unicamp.br/~lehilton/mc102qr/tarefas/13-algoritmos-eficientes.html
                            https://ic.unicamp.br/~lehilton/mc102qr/tarefas/12-colecoes-dinamicas.html
                              https://ic.unicamp.br/~lehilton/mc102qr/tarefas/11-dicionarios-e-tuplas.html
                                https://ic.unicamp.br/~lehilton/mc102qr/tarefas/10-imagens-binarias.html
                                  https://ic.unicamp.br/~lehilton/mc102qr/tarefas/09-conceito-frequencia.html
                                    https://ic.unicamp.br/~lehilton/mc102qr/tarefas/08-funcoes.html
                                      https://ic.unicamp.br/~lehilton/mc102qr/tarefas/07-percorrer-listas.html
                                        https://ic.unicamp.br/~lehilton/mc102qr/tarefas/06-listas.html
                                          https://ic.unicamp.br/~lehilton/mc102qr/tarefas/05-condicional.html
                                            https://ic.unicamp.br/~lehilton/mc102qr/tarefas/04-entendendo-algoritmos.html
                                              https://ic.unicamp.br/~lehilton/mc102qr/tarefas/03-estruturas-controle.html
                                                https://ic.unicamp.br/~lehilton/mc102qr/tarefas/02-problemas-algoritmos.html
                                                  https://ic.unicamp.br/~lehilton/mc102qr/tarefas/01-primeira-tarefa.html