Na primeira atividade da aula não precisamos lidar com o conteúdo e a estrutura da página que estávamos capturando. Como o conteúdo que nos interessava estava em uma tabela, e o pacote rvest contém uma função específica para extração de tabelas, gastamos poucas linhas de código para ter a informação capturada já organizada em um data frame.
O que fazer, entretanto, com páginas que não têm tabelas? Como obter apenas as informações que nos interessam quando o conteúdo está “espalhado” pela página? Utilizaremos, como veremos abaixo, a estrutura do código HTML da própria página para selecionar apenas o que desejamos e construir data frames.
Nosso objetivo nessa atividade será capturar uma única página usando a estrutura do código HTML da página. Já sabemos que, uma vez resolvida a captura de uma página, podemos usar “loop” para capturar quantas quisermos, desde que tenham uma estrutura semelhante.
Antes disso, porém, precisamos falar um pouco sobre XML e HTML.
XML significa “Extensive Markup Language”. Ou seja, é uma linguagem – e, portanto, tem sintaxe – e é uma linguagem com marcação. Marcação, neste caso, significa que todo o conteúdo de um documento XML está dentro de “marcas”, também conhecidas como “tags”. É uma linguagem extremamente útil para transporte de dados – por exemplo, a Câmara dos Deputados utiliza XML em seu Web Service para disponibilizar dados abertos (mas você não precisa saber disso se quiser usar o pacote de R bRasilLegis que desenvolvemos) – disponível aqui: https://github.com/leobarone/bRasilLegis.
Por exemplo, se quisermos organizar a informação sobre um indivíduo que assumiu diversos postos públicos, poderíamos organizar a informação da seguinte maneira:
<politicos>
<politico>
<id> 33333 </id>
<nome> Fulano Deputado da Silva </nome>
<data_nascimento> 3/3/66 </data_nascimento>
<sexo> Masculino </sexo>
<cargos>
<cargo>
<cargo> prefeito </cargo>
<partido> PAN </partido>
<ano_ini> 2005 </ano_ini>
<ano_fim> 2008 </ano_fim>
</cargo>
<cargo>
<cargo> deputado federal </cargo>
<partido> PAN </partido>
<ano_ini> 2003 </ano_ini>
<ano_fim> 2004 </ano_fim>
</cargo>
<cargo>
<cargo> deputado estadual </cargo>
<partido> PAN </partido>
<ano_ini> 1998 </ano_ini>
<ano_fim> 2002 </ano_fim>
</cargo>
</cargos>
</politicos>
</politicos>
Exercício (difícil): se tivessemos que representar estes dados em um banco de dados (data frame), como seria? Quantas linhas teria? Quantas colunas teria?
Veja no link abaixo um exemplo de arquivo XML proveniente do Web Service da Câmara dos Deputados:
Abra agora a página inicial da Folha de São Paulo. Posicione o mouse em qualquer elemento da página e, com o botão direito, selecione “Inspecionar” (varia de navegador para navegador, mas o melhor é sempre usar o Firefox. Se estiver utilizando Internet Explorer, saia já daí). Você verá o código HTML da página.
Sem precisar observar muito, é fácil identificar que o código HTML da Folha se assemelha ao nosso breve exemplo de arquivo XML. Não por acaso: HTML é um tipo de XML. Em outra palavras, toda página de internet está em um formato de dados conhecido e, como veremos a seguir, pode ser re-organizado facilmente.
O fato de haver hierarquia nos códigos XML e HTML nos permite construir “caminhos”, como se fossem caminhos de pastas em um computador, dentro do código.
Por exemplo, o caminho das “tags” que contêm a informação “nome” em nosso exemplo fictício é:
/politicos/politico/nome
O caminho das “tags” que contêm a informação “partido” em nosso exemplo fictício, por sua vez, é:
/politicos/politico/cargos/cargo/partido
Seguindo tal caminho chegamos às três “tags” que contém a informação desejada.
Simples, não? Mas há um problema: o que fazer quando chegamos a 3 informações diferentes (o indivíuo em nosso exemplo foi eleito duas vezes pelo PAN e uma pelo PRONA)? Há duas alternativa: a primeira, ficamos com as 3 informações armazenadas em um vetor, pois as 3 informações interessam. Isso ocorrerá com frequência.
Mas se quisermos apenas uma das informações, por exemplo, a de quando o indivíduo foi eleito deputado estadual? Podemos usar os atributos e os valores dos atributos das tag para construirmos o caminho. Neste caso, teríamos como caminho:
/politicos/politico/cargos/cargo[@tipo = 'deputado estadual']/partido
Guarde bem este exemplo: ele será nosso modelo quando tentarmos capturar páginas.
Vamos supor que queremos poupar nosso trabalho e sabemos que as únicas “tags” com nome “partido” no nosso documento são aquelas que nos interessam (isso quase nunca é verdade em um documento HTML). Podemos simplicar nosso caminho de forma a identificar “todas as ‘tags’, não importa em qual nível hierarquíco do documento”. Neste caso, basta usar duas barras:
//partido
Ou “todas as tags ‘partido’ que sejam descendentes de ‘politico’, não importa em qual nível hierarquíco do documento”:
/politicos/politico//partido
Ou ainda “todas as tags ‘partido’, , não importa em qual nível hierarquíco , que sejam descendentes de quaisquer tag ‘politico’, também não importando em qual nível hierarquíco do documento”:
//politico//partido
Ou “todas as ‘tags’ filhas de qualquer ‘tag’ ‘cargo’” (usa-se um asterisco para indicar ‘todas’):
//cargo/*
Observe o potencial dos “caminhos” para a captura de dados: podemos localizar em qualquer documento XML ou HTML uma informação usando a própria estrutura do documento. Não precisamos organizar o documento todo, basta extrair cirurgicamente o que queremos – o que é a regra na raspagem de páginas de internet.
Vamos entrar na página principal da Folha de São Paulo e fazer uma pesquisa simples na caixa de busca – exatamente como faríamos em um jornal ou qualquer outro portal de internet (o processo seria o mesmo em buscadores como Google ou DuckDuckGo). Por exemplo, vamos pesquisar a palavra “merenda”. A ferramenta de busca nos retorna uma lista de links que nos encaminharia para diversos documentos ou páginas da ALESP relacionadas ao termo buscado.
Nosso objetivo é construir um vetor com os links dos resultados. Em qualquer página de internet, links estão dentro da tag “a”. Uma maneira equivocada de encontrar todos os links da página usando “caminhos em XML” seria:
//a
Entretanto, há diversos outros elementos “clicáveis” na página além dos links que nos interessam – por exemplo, as barras laterais, o banner com os logotipos, os links do mapa do portal, etc. Precisamos, portanto, especificar bem o “caminho” para que obtivéssemos apenas os links que nos interessam.
Infelizmente não temos tempo para aprender HTML com profundidade, mas podemos usar lógica e intuição para obter caminhos unívocos. Neste exemplo, todos as “tags” “a” que nos interessam são filhas de alguma tag “div”, que por sua vez é filha de outra “div”, esta filha de “li” (que é abreviação de “list” e indica um único elemento de uma lista). Podemos melhorar nosso caminho:
//li/div/div/a
A tag li, por sua vez, é filha da tag “ol” (“ordered list”), ou seja, é a tag que dá início à lista não ordenada formada pelos elementos “li”. Novamente, melhoramos nosso caminho:
//ol/li/div/div//a
E se houver mais de uma “ordered list” na página? Observe que essa tag “ol” tem atributos: class=“u-list-unstyled c-search”. Bem específico, não?
Alguns atributos têm “função” para o usuário da página – por exemplo, as tags “a” contém o atributo “href”, que é o link do elemento “clicável”. Mas, em geral, em uma página de internet os atributos não fazem nada além de identificar as tags para a programadora. Diversos programas para construção de páginas criam atributos automaticamente. Por exemplo, se vocë fizer um blog em uma ferramenta qualquer de construção de blogs, sua página terá tags com atributos que você sequer escolheu.
As tags mais comum em páginas HTML são: head, body, div, p, a, table, tbody, td, ul, ol, li, etc. Os atributos mais comuns são: class, id, href (para links), src (para imagens), etc. Em qualquer tutorial básico de HTML você aprenderá sobre elas. Novamente, não precisamos aprender nada sobre HTML e suas tags. Apenas precisamos compreender sua estrutura e saber navegar nela.
Voltando ao nosso exemplo, se usarmos o atributo para especificar o “caminho” para os links teremos:
//ol[@class='u-list-unstyled c-search'/li/div/div/a
Pegou o espírito? Vamos agora dar o nome correto a este “caminho”: xPath.
Vamos agora voltar ao R e aprender a usar os caminhos para criar objetos no R.
O primeiro passo na captura de uma página de internet é criar um objeto que contenha o código HTML da página. Para tanto, usamos a função read_html do pacote rvest, que utilizamos na aula anterior. Vamos usar a segunda página da busca pela palavra “merenda” na Folha de São Paulo como exemplo:
library(rvest)
url_folha <- 'http://search.folha.uol.com.br/search?q=merenda&site=todos&results_count=3769&search_time=0.033&url=http%3A%2F%2Fsearch.folha.uol.com.br%2Fsearch%3Fq%3Dmerenda%26site%3Dtodos&sr=26'
pagina <- read_html(url_folha)
Note que a estrutura do endereço URL é relativamente simples: “q” é o primeiro parâmetro e informa o texto buscado. “site=todos”, informa que a busca é feita em todas as páginas do grupo Folha/UOL. “results_count”, é o total de resultados e “search_time” o tempo que demorou para realização da busca. “url” é o próprio endereço. E, muito importante, “sr” é o número do primeiro resultado da página, que, no caso da Folha, pula de 25 em 25. Nesta atividade vamos capturar apenas a página 2, mas você já aprendeu na atividade anterior como capturar todas as páginas usando loops.
class(pagina)
Observe (usando a função “class”) que o objeto “pagina” que contém o HTML da página em análise pertence às classes “xml_document” e “xml_node”. Ou seja, o R sabe que este objeto é um XML e, portanto, é capaz de identificar a estrutura do documento – tags, atributos, valores e conteúdos.
Vamos agora aprender a “navegar” em um objeto XML dentro do R e extrair dele apenas as informações que nos interessam. Estas informações podem estar no conteúdo das tags (“text”) ou nos atributos (“attr”).
Voltando ao nosso exemplo da busca na Folha de São Paulo, vamos obter os títulos e os links das notícias, cujo caminho construímos acima. Já temos o conteúdo da página capturado no objeto “pagina”.
Em primeiro lugar, com o caminho do título e a função html_nodes, extraímos os “nodes” com as “tags” que nos interessam. Além disso, convém especificar a última ‘div’ do xpath, pois há mais de uma.
nodes_titulos <- html_nodes(pagina, xpath = '//ol/li/div/div[@class="c-headline__content"]/a/h2')
Use a função “print” para observar o que capturamos.
Agora, tendo apenas os “nodes” que nos interessam por conter os títulos das notícias (e seus elementos clicáveis), usamos a função html_text para extrair os títulos:
titulos <- html_text(nodes_titulos)
View(titulos)
E a função html_attr para extrair os atributos “href”, que contêm os títulos das notícias. Vamos repetir o caminho para chegar aos links, mas retiraremos o ‘h2’ do final do caminho.
nodes_links <- html_nodes(pagina, xpath = '//ol/li/div/div[@class="c-headline__content"]/a')
links <- html_attr(nodes_titulos, name = "href")
Note que uma “tag” pode conter mais de um atributo e por isso usamos o argumento “name” da função html_attr para especificar qual atributo queremos.
Veja que as funções html_text e html_attr cumprem a mesma tarefa da função html_table: retirar de um objeto XML (que é uma página capturada) as informações que nos interessam.
O resultado de ambas funções é um vetor com todos os títulos e links das notícias, respectivamente. Podemos colocar os vetores lado a lado (verticalmente) e criar um data_frame que contém duas variáveis, título e link da notícia:
tabela_titulos <- data.frame(titulos, links)
Use a função View para visualizar os dados capturados.
O desafio a partir de agora é conectar o que aprendemos da raspagem de dados de várias páginas com “for loop”, mas usando a função html_table, com as novas funções de raspagem de páginas que extraem com precisão o que conteúdo que nos interessa. Esta será nossa próxima atividade.