Avançado Tutoriais de R

Wep Scraping e Download de Dados Automático – Parte II

4-Download_de_Dados_e_Web_Scraping_Pt_II.knit

key words: Web Scraping, Download de dados, ETL

Entendo estruturas HTML e funcionalidades básicas do pacote rvest

Alguns sites não disponibilizam o download estruturado de dados. Isto é, que permite uma conversão fácil para uma estrutura de dados padrão como data frames, matrizes, etc. O conteúdo de sites disponíveis no próprio endereço da Web comumente utiliza a linguagem HTML para visualização do usuário por meio de um navegador.

Existem dois conceitos chaves relacionados a estrutura de comunicação entre uma máquina cliente e um servidor:

  • Uma requisição GET ocorre quando a máquina cliente envia uma url ao servidor passando parâmetros de consulta na própria url Por isso, nesse caso, os parâmetros são visíveis na url.

  • Uma requisição POST ocorre quando a máquina cliente envia uma url ao servidor passando parâmetros de consulta no corpo da solicitação. Normalmente, ele é utilizado quando o usuário necessita preencher algum formulário para que a requisição seja aceita pelo servidor.

O pacote rvest auxilia no envio dessas requisições e obtenção dessas informações e facilita a conversão para modelos de dados estruturados. Porém, antes de utilizá-lo cabe algumas considerações de conceitos relacionados a linguagem HTML.

O HTML é uma linguagem utilizada para construção de páginas na Web. A estrutura básica é composta por tags que indicam qual o tipo de conteúdo deve ser exibido. Por exemplo, títulos, tabelas, textos corridos, etc.

Cada tag possui um conjunto de “sub tags” ou filhos, que correspondem ao conteúdo daquela seção. Uma tag é aberta pelo comando <nome da tag> e fechada <’/’nome da tag>, como uma espécie de marcação de início e fim da seção.

Vamos ao seguinte exemplo.

library(rvest)
library(xml2)

html_ex<-"<!DOCTYPE html>
<html>
<h1>
TITULO DA PAGINA
</h1>

<p>
Primeiro paragrafo apresentado apos o titulo
</p>

<table border-collapse= collapse width= 100% border= '1px solid #dddddd'>
  <tr>
    <th>Nome</th>
    <th>Sobrenome</th>
    <th>Cidade</th>
    <th>ID Cliente</th>
  </tr>
  <tr>
    <td>Kauan</td>
    <td>Gusman</td>
    <td>Sao Paulo</td>
    <td>1</td>
  </tr>
  <tr>
    <td>Jonas</td>
    <td>Matias</td>
    <td>Sorocaba</td>
    <td>2</td>
  </tr>
  <tr>
    <td>Vitor</td>
    <td>Castro</td>
    <td>Belo Horizonte</td>
    <td>3</td>
  </tr>
</table>

<p>

</p>

<body>
Sequencia do conteudo da pagina.
</body>

</html>"

html_file<-htmltools::HTML(html_ex) %>% read_html()

O código acima cria um documento simples de HTML. Você pode (e recomendamos que faça) ver seu resultado clicando aqui. Copie e cole o código do objeto html_ex e veja a página gerada.

Nesse código temos as seguintes tags expostas: html, h1, p, table, tr, td e body. Essencialmente (mas não somente) o que o pacote rvest nos permite é acessar o conteúdo de cada uma dessas tags.

Vamos a uma lista das principais funções do pacote e suas funcionalidades:

Funções do pacote rvest
Função Descrição
html_session Simula uma sessão com um navegador permitindo receber e enviar informações a um servidor
html_nodes Extrai tags de um HTML utilizando endereço XPath ou seletores CSS.
html_table Extrai e converte uma tag do tipo table para um data frame.
html_text Converte o conteúdo de um objeto HTML para um texto.
html_attr Extrai atributos de uma tag.
html_form Extrai as tags to tipo form de um objeto HTML.
set_value Altera o valor de entrada de uma tag do tipo form.
read_html Lê um arquivo HTML e permite extração de fragmentos.
jump_to Permite migrar uma sessão atualmente em execução para um novo url a partir do link fornecido pelo usuário.
follow_link Permite migrar uma sessão atualmente em execução para um novo url a partir do link fornecido por uma tag .
config Função do pacote httr (utilizado pelo rvest). Será útil para definição de proxy, cookies, portas, entre outras configurações necessárias para acessar o navegador, principalmente em ambientes de navegação protegidos cujo usuário não é administrador da máquina

Veja o resultado da aplicação de algumas dessas funções abaixo.

html_file %>% html_nodes("*") %>% html_name() %>% unique() ## Lista todas as Tags presentes no objeto HTML
## [1] "body"  "h1"    "p"     "table" "tr"    "th"    "td"
html_file %>% html_nodes("table") %>% html_table(fill = TRUE) ## Extrai todas as tags table do objeto HTML e converte-os para uma lista de data frames
## [[1]]
## # A tibble: 3 x 4
##   Nome  Sobrenome Cidade         `ID Cliente`
##   <chr> <chr>     <chr>                 <int>
## 1 Kauan Gusman    Sao Paulo                 1
## 2 Jonas Matias    Sorocaba                  2
## 3 Vitor Castro    Belo Horizonte            3
html_file %>% html_nodes("h1") %>% html_text() ## Extrai o conteúdo da tag h1 e converte em um arquivo de texto
## [1] "\nTITULO DA PAGINA\n"
html_file %>% html_nodes("table") %>% html_attr("width") ## Extrai o atributo de largura da tag table
## [1] "100%"
html_file %>% html_nodes("table,td") %>% html_text() ## Extrai da tag table as sub tags td
##  [1] "Nome\n    Sobrenome\n    Cidade\n    ID Cliente\n  Kauan\n    Gusman\n    Sao Paulo\n    1\n  Jonas\n    Matias\n    Sorocaba\n    2\n  Vitor\n    Castro\n    Belo Horizonte\n    3\n  "
##  [2] "Kauan"                                                                                                                                                                                   
##  [3] "Gusman"                                                                                                                                                                                  
##  [4] "Sao Paulo"                                                                                                                                                                               
##  [5] "1"                                                                                                                                                                                       
##  [6] "Jonas"                                                                                                                                                                                   
##  [7] "Matias"                                                                                                                                                                                  
##  [8] "Sorocaba"                                                                                                                                                                                
##  [9] "2"                                                                                                                                                                                       
## [10] "Vitor"                                                                                                                                                                                   
## [11] "Castro"                                                                                                                                                                                  
## [12] "Belo Horizonte"                                                                                                                                                                          
## [13] "3"
html_file %>% html_nodes(xpath = '//table//td') %>% html_text() ## Extrai da tag table as sub tags td utilizando XPath
##  [1] "Kauan"          "Gusman"         "Sao Paulo"      "1"             
##  [5] "Jonas"          "Matias"         "Sorocaba"       "2"             
##  [9] "Vitor"          "Castro"         "Belo Horizonte" "3"
html_file %>% html_nodes(xpath = '//table//tr[2]//td[3]') %>% html_text() ## Extrai a terceira célula da segunda linha da tabela (sendo a primeira o cabeçalho) utilizando XPath
## [1] "Sao Paulo"

Veja que para acessar as diferentes informações inseridas no documento é necessário entender como as camadas foram construídas. É possível extraí-los utilizando CSS Selectors ou comandos XPath. Agora você conhece a estrutura básica de um objeto HTML e sabe como o pacote rvest permite interagir com as diferentes camadas dessa estrutura.

Coletando manchetes de um site de notícias

O primeiro exemplo prático consiste no exercício de extrair notícias de um endereço da Web.

Para isso, será necessário identificar o caminho dos elementos que desejamos extrair, isto é, o conjunto de CSS Selectors ou XPath que acessa-os. Uma forma fácil de fazer isso utiliza uma funcionalidade do próprio navegador. Para isso, siga os seguintes passos:

  • Clique com o botão direito do mouse em cima do objeto que deseja extrair (tabela, texto, etc).
  • Clique com o botão esquerdo do mouse na opção Inspecionar (ou algo derivado disso).
  • Uma nova janela irá abrir com o endereço desse elemento. Informações como tag, classe, e outros atributos serão visíveis.
  • Se você estiver utilizando o google chrome é possível copiar os seletores ou XPath do objeto diretamente. Para isso, clique com o botão direto do mouse sobre o texto destacado na nova janela. Siga para “copiar” e escolha a opção desejada.

Feito o reconhecimento do caminho HTML que nós leva ao elemento a ser extraído, podemos seguir para o R. Os procedimentos a seguir executam essa tarefa.

url<-"https://valor.globo.com/"

site_noticia<-url %>% html_session() ## Cria a sessão com o navegador

## A tag "a" com classe "bstn-dedupe-url" é a que guarda o título das notícias que vamos extrair. Veja o código fonte da página e use Ctrl+F para identificar esse elemento.

links<-site_noticia %>% html_nodes("a.bstn-dedupe-url") ## Extrai todos os elementos com classe igual a "bstn-dedupe-url" da tag "a" utilizando CSS Selectors

## site_noticia %>% html_nodes(xpath = '//a[@class="bstn-dedupe-url "]') ## Extrai todos os elementos com classe igual a "bstn-dedupe-url" da tag "a" utilizando XPath

noticias <- data.frame(
                      "Titulo"=links %>% html_text(trim = TRUE), ## Extrai o títulos das notícias
                      "Link"=links %>% html_attr("href")         ## Extrai o link das notícias
)
5 primeiras Notícias Coletadas
Titulo Link
Início do aperto monetário nos EUA torna incertas perspectivas para emergentes, diz FMI https://valor.globo.com/financas/noticia/2022/01/10/inicio-do-aperto-monetario-nos-eua-torna-incertas-perspectivas-para-emergentes-diz-fmi.ghtml
Goldman Sachs estima que Fed vai elevar juro americano quatro vezes em 2022 https://valor.globo.com/financas/noticia/2022/01/10/goldman-sachs-estima-que-fed-vai-elevar-juro-americano-quatro-vezes-em-2022.ghtml
Cesp será avaliada em R$ 9,1 bi em negócio com Votorantim e CPPIB https://pipelinevalor.globo.com/negocios/noticia/cesp-sera-avaliada-em-r-91-bi-em-negocio-com-votorantim-e-cppib.ghtml
Investimento ganha força com leilões e commodities https://valor.globo.com/empresas/noticia/2022/01/10/investimento-ganha-forca-com-leiloes-e-commodities.ghtml
Energia atrai bilhões e pode ter privatização da Eletrobras https://valor.globo.com/empresas/noticia/2022/01/10/energia-atrai-bilhoes-e-pode-ter-privatizacao-da-eletrobras.ghtml

É possível utilizar o rvest para navegar entre páginas. Coletando urls disponíveis na sessão inicialmente aberta e seguindo para novos endereços. Com isso, seria possível utilizar os links coletados anteriormente para obter as notícias na integra, por exemplo.

Vamos refazer o processo anterior coletando as manchetes disponíveis na seção de finanças do Valor Econômico. Os seguintes procedimentos executam a tarefa.

novo_url<-site_noticia %>% html_nodes(xpath = "//li[@id='menu-1-financas']//a[1]") %>% html_attr("href") %>% .[1]  ## Obtem o novo url da página a ser aberta

site_noticia<-jump_to(site_noticia, novo_url) ## Envia uma requisição para que a sessão migre para o novo url

links<-site_noticia %>% html_nodes("a.bstn-dedupe-url") ## Extrai todos os elementos com classe igual a "bstn-dedupe-url" da tag "a" utilizando CSS Selectors

noticias <- data.frame(
                      "Titulo"=links %>% html_text(trim = TRUE), ## Extrai o títulos das notícias
                      "Link"=links %>% html_attr("href")         ## Extrai o link das notícias
)
5 primeiras Notícias da seção de Finanças
Titulo Link
Início do aperto monetário nos EUA torna incertas perspectivas para emergentes, diz FMI https://valor.globo.com/financas/noticia/2022/01/10/inicio-do-aperto-monetario-nos-eua-torna-incertas-perspectivas-para-emergentes-diz-fmi.ghtml
Fim de estímulos põe ativos de risco contra a parede https://valor.globo.com/financas/noticia/2022/01/10/fim-de-estimulos-poe-ativos-de-risco-contra-a-parede.ghtml
Juros futuros recuam e dólar comercial tem leve alta no início dos negócios https://valor.globo.com/financas/noticia/2022/01/10/juros-futuros-recuam-e-dolar-comercial-tem-leve-alta-no-inicio-dos-negocios.ghtml
Fundo imobiliário mostra resistência mesmo na crise https://valor.globo.com/financas/noticia/2022/01/10/fundo-imobiliario-mostra-resistencia-mesmo-na-crise.ghtml
XP compra Modal e acirra disputa https://valor.globo.com/financas/noticia/2022/01/10/xp-compra-modal-e-acirra-disputa.ghtml

Coletando informações de indicadores financeiros do site da B3

O segundo exemplo tem como objetivo coleta de algumas taxas diretamente do site da B3.

Inicialmente coletaremos a curva futura de juros, resultante dos contratos negociados na B3 cujo objeto é a taxa DI. Para isso, teremos que enviar uma requisição do tipo GET preenchendo alguns parâmetros de consulta, são eles: O código da taxa pesquisada e a data de atualização.

url="http://www2.bmf.com.br/pages/portal/bmfbovespa/boletim1/TxRef1.asp"

site_B3<- url %>% html_session()

form_b3<- site_B3 %>% html_form() %>% .[[1]] ## ver todos os parâmetros do formulário

O comando html_form permite visualizar quaisquer parâmetros de formulários presentes no URL. É possível alterar esses parâmetros e resubmeter os formulários utilizando uma requisição POST que, utilizando algumas funções alteraria os parâmetros da consulta utilizado pela requisição GET. Iremos fazer o segundo passo diretamente nesse caso.

Primeiramente, iremos obter uma lista das opções disponíveis para consulta no site.

Opcoes<-data.frame(
  "Taxa"=site_B3 %>% html_nodes(xpath = '//table//select[@name="slcTaxa"]//option') %>% html_text(trim = TRUE), ## Opções de taxas que visíveis para o usuário
  "Cod Taxa"=site_B3 %>% html_nodes(xpath = '//table//select[@name="slcTaxa"]//option') %>% html_attr("value") ## Código das taxas que são utilizadas como parâmetro de consulta
)

head(Opcoes)
##           Taxa Cod.Taxa
## 1 Ajuste cupom      ACC
## 2     Alumínio      ALD
## 3   DI x Anbid       AN
## 4  Anbid x pré      ANP
## 5   Ajuste pré      APR
## 6      IBrX-50      BRP

Agora, podemos seguir com a requisição GET e obtenção dos dados. Deveremos informar o código da taxa desejada (slcTaxa) e a data de atualização (Data e Data1). O código PRE, representa a taxa DI (o qual é o padrão de abertura da página).

consulta <- list(slcTaxa="PRE", 
                Data1= "20220105", 
                Data="05/01/2022")  ## Parâmetros de consulta sempre devem ser um objeto list

# requisicao de busca
result <- httr::GET(url, query = consulta)  ## Busca o url utilizando os parâmetros de consulta determinados

tb=result %>% read_html() %>%
  html_nodes("table") %>%
  html_table(fill = TRUE, dec=",", header=FALSE)  ## Obtem os dados e converte-os em data frame

Utilizando o comando result$url é possível ver que o url foi modificado e os parâmetros da consulta constam em sua definição. Isso ocorre pela comunicação se dar via requisição do tipo GET.

Infelizmente o resultado dessa consulta não facilita uma conversão direta para uma estrutura de dados analítica. Alguns tratamentos são necessários os quais podem ser vistos abaixo. Caso julgue necessário para entendimento, acesse nosso tutorial de Manuseio de Estrutura de Dados.

tb_aux<-data.frame("Valor"=as.numeric(t(as.data.frame(tb[2])[,-1])[-c(1:6),-2]))

colDias<-seq(3, nrow(tb_aux), 3)
colCDI252<-seq(1, nrow(tb_aux), 3)

dados<-data.frame("Dias Corridos"=c(1,tb_aux[colDias,][-length(tb_aux[colDias,])]),"CDI 252"=tb_aux[colCDI252,])

head(dados)
##   Dias.Corridos CDI.252
## 1             1    9.15
## 2             7    9.15
## 3            12    9.15
## 4            14    9.15
## 5            16    9.15
## 6            21    9.15

Vamos buscar uma nova taxa utilizando a estrutura anterior. Buscaremos a Libor, taxa juros de empréstimo interbancário de instituições que operam em Londres.

consulta <- list(slcTaxa="LIB", 
                Data1= "20220105", 
                Data="05/01/2022")  ## Alterando a taxa consultada para Libor

# requisicao de busca
result <- httr::GET(url, query = consulta)  ## Busca o url utilizando os parâmetros de consulta determinados

tb=result %>% read_html() %>%
  html_nodes("table") %>%
  html_table(fill = TRUE, dec=",", header=FALSE)  ## Obtem os dados e converte-os em data frame

Alterando um pouco os tratamentos executados anteriormente obtemos um formato de estrutura de dados analítica.

tb_aux<-data.frame("Valor"=as.numeric(t(as.data.frame(tb[2])[,-1])[-c(1:3),-2]))

colDias<-seq(1, nrow(tb_aux)-1, 2)
colLib<-seq(2, nrow(tb_aux), 2)

dados<-data.frame("Dias Corridos"=tb_aux[colDias,],"Libor"=tb_aux[colLib,])

head(dados)
##   Dias.Corridos Libor
## 1             1 0.229
## 2             7 0.229
## 3            12 0.229
## 4            14 0.229
## 5            16 0.229
## 6            21 0.229

Muitos sites mais modernos utilizam estruturas de comunicação baseadas em javascript. O rvest tem seu uso limitado nesses casos. A solução é simular a utilização de um navegador por meio de outras ferramentas disponíveis no R. A principal delas é o pacote RSelenium que será tema de um tutorial futuro.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *