forked from antrologos/mq_2018_WebScraping
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mq_ufmg_2018_tutorial08.Rmd
400 lines (252 loc) · 23.6 KB
/
mq_ufmg_2018_tutorial08.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# Tutorial 8 - Cookies, sessions e formulários na web. Navegue na internet com o R!
_Autores_: Leonardo Sangali Barone e Rogério Jerônimo Barbosa
Até agora trabalhamos com exemplos nos quais retiramos informação de páginas em html, mas não enviamos nenhuma informação ao servidor com as quais estamos nos comunicando (exceto manualmente). Contudo, é muito comum nos depararmos com formulários em páginas que queremos raspar. Formulários, na maioria das vezes, aparecerão como caixas de consulta acompanhada de um botão.
Mecanismos de busca (Google, DuckDuckGo, etc) têm formulários nas suas páginas iniciais. Portais de notícia ou de Legislativos têm formulários de busca (como o que usamos manualmente no caso da Folha de São Paulo). Por vezes, mesmo para "passar" de página nos deparamos com um formulário.
Neste tutorial vamos aprender a preencher um formulário, enviá-lo ao servidor da página e capturar sua resposta.
Começaremos com um exemplo simples, como o buscador da Google, e depois faremos um exercício bastante mais complexo com o STF.
## Cookies e Sessions
Guarde bem essas duas palavras: _cookies_ e _sessions_. Elas representam conceitos fundamentais para uma adequada compreensão sobre o funcionamento da internet, dos navegadores -- e importantíssimos para a raspagem de dados ( _Web_ _Scraping_ ) de certas páginas.
### Cookies
**Cookies** são pequenos arquivos de texto que guardam informações necessárias para a sua navegação. Por exemplo: se você vai até o site do IBGE e escolhe a opção de vê-lo na versão em inglês, como o IBGE sabe que a partir dali todas as próximas páginas e opções também deverão ser apresentadas em inglês? No momento em que você clicou naquela opção, o seu navegador automaticamente baixou um arquivo que guarda características e opções que serão usadas novamente depois. Frequentemente, é também por meio de cookies que são guardadas informações sobre o que está na sua "cesta de compras", quando você marca produtos que deseja adquirir num site de vendas. Cookies são muito úteis e importantes -- essenciais para a navegação.
Até agora, quando queremos raspar dados de uma lista com várias páginas de resultado, fizemos sempre alterações na própria URL, informando o número da página que desejamos acessar. Mas nem sempre isso é possível, pois nem todos os sites guardam no próprio endereço a informação sobre o número da página em que estamos. Não raro, essa informação está guardada num cookie! Sim, um pequeno arquivo de texto, guardado em algum lugar do seu próprio computador, traz informações que serão dinamicamente acessadas por seu navegador e atualizadas.
Talvez você já tenha ouvido algo bastante ruim sobre cookies por aí... dizendo até que são usados por hackers etc. A história é mais complicada do que isso... A princípio, somente o site que gerou o cookie pode consultá-lo para saber sobre suas opções. Mas, às vezes, esse site pode passar essas informações para outro (várias empresas são associadas, certo?). Então, quando você vai até a Amazon e escolhe alguns produtos para sua cesta, pode ser que, algum tempo depois você veja aqueles mesmos itens num anúncio na página do Google ou até de outro lugar. Provavelmente aquela informação estava num cookie e a Amazon pode ter liberado o acesso para outra empresa. O objetivo, é tornar sua navegação mais customizada e personalizada, oferecendo para você apenas o que é relevante. As empresas querem vender para você aquilo que você realmente tem probabilidade de comprar...
Este pequeno vídeo [aqui](https://www.youtube.com/watch?v=I01XMRo2ESg) (em inglês) traz um bom resumo e panorama sobre o que são cookies. Quer algo um pouquinho mais técnico? Veja este curto vídeo [aqui](https://www.youtube.com/watch?v=LHSSY8QNvew) então.
"Roubar" informações de cookies é possível. Mas não é isso o que está ocorrendo quando você visita um site e os anúncios de coisas que você já viu estão lá. Quer saber mais sobre roubo de Cookies? Veja este vídeo [aqui](https://www.youtube.com/watch?v=T1QEs3mdJoc).
Cookies, no entanto, devem ser pequenos. Afinal, são informações continuamente trocadas entre você (cliente) e o computador que armazena o site no qual você navega (servidor). Se ele fosse um arquivo grande, o fluxo de uploads e downloads seriam muito intenso e a navegação se tornaria muito mais lenta. Por esta razão, existem **sessions**, que servem para guardar conteúdos maiores.
### Sessions
**Sessions** são a relação estabelecida entre o servidor (o site) e o cliente (o seu navegador). Um arquivo ou um conjunto de arquivos guardam um complexo de informações sobre você -- que vão muito além da capacidade dos cookies (que usualmente não podem ultrapassar 4kb). Essas informações podem estar guardadas tanto localmente (no seu próprio coputador) como remotamente (no servidor). Se estiverem guardadas localmente, a navegação é geralmente mais rápida -- visto que você não precisa trocar requisições usualmente com o servidor.
Entenda as sessions como uma espécie de "conta" que você abre no servidor (dessas contas que uma pessoa pode abrir num estabelecimento de comércio e que guardam suas informações e interações). E os cookies são usados nesse caso apenas como uma espécie de ID (seu cartão de identidade) para registrar você frente ao servidor.
Quando você loga na sua conta de e-mail, está abrindo uma session. Está dizendo ao seu navegador para estabelecer essa relação duradoura com o servidor (o site do Gmail, por exemplo). Assim, quando você navega dentro do seu email, não precisa a todo momento fazer o login de novo. Suas informações estão guardadas nesse conjunto de arquivos que representa a session. E cookies serão frequentemente usados, para mostrar ao site do Gmail o seu ID.
Quer saber mais sobre sessions? Neste [vídeo](https://www.youtube.com/watch?v=64veb6tKTm0) (em inglês) há uma rápida e intuitiva apresentação.
## _rvest_, formulários e Google
Agora, com aqueles dois conceitos na ponta da língua -- **cookies** e **sessions** -- vamos passar às nossas análises.
Vamos começar carregando o pacotes _rvest_:
```{r}
library(rvest)
```
Vamos explorar o buscador do Google. Isso mesmo, vamos fazer uma busca no Google a partir do R! O buscador do Google é constituído basicamente de um campo de texto que deve ser preenchido e enviado de volta ao servidor. Quando temos que informar qualquer tipo de informação e enviar de volta (mesmo que seja apenas marcar uma opção de "ok"), estamos preenchendo um **formulário**.
Este é justamente um caso em que termemos estabelecer uma conexão com o servidor. O Google exige o estabelecimento de uma **session** -- e isso é feito antes mesmo de capturar a página na qual o formulário está.
Utilizamos a função _html\_session_ para isso:
```{r}
google_url <- "https://www.google.com"
google_session <- html_session(google_url)
```
Estabelecida a conexão, precisamos conhecer o formulário. Começamos, obviamente, obtendo o código HTML da página do formulário, tal como sempre fizemos. Mas desta vez, ao invés de passar a própria URL da página como argumento principal da função, passamos o objeto que contém as informações da session estabelecida.
Veja: o objeto `google_session` guarda, além das informações sobre a conexão, também o próprio conteúdo HTML.
```{r}
read_html(google_session)
```
O objeto `google_session` pode ser alvo de nossas atividades de raspagem e coleta, sem que precisemos executar sobre ele novamente a extração do conteúdo HTML. Esse conteúdo já está lá!
Se quiséssemos raspar todos os links da página, faríamos:
```{r}
html_nodes(google_session, xpath = "//a")
```
Nesse caso, nosso interesse é extrair formulário, isto é o trecho de HTML que contém o campo de busca onde digitamos o que queremos que o Google encontre para nós. Como tabelas em HTML, fomrulários tem suas tags próprias: `html <form>` e `html </form>`. E contamos, no pacote _rvest_, com uma função que extrai uma lista contendo todos os formulários da página:
```{r}
google_form_list <- html_form(google_session)
google_form_list
```
O resultado da função `html_form` é uma lista (observe o `[[1]]` no topo dos resultados), tal como também ocorria no `html_table`.
No caso do buscador da Google, há apenas um formulário na página. Com dois colchetes, extraímos então o item que está na primeira posição da lista de formulários (você verá que no próximo exemplo, do site do STF, obteremos mais de um formulário e precisaremos identificar qual queremos).
```{r}
google_form <- google_form_list[[1]]
class(google_form)
google_form
```
Examine o objeto que contém o formulário. Ele é um objeto da classe "form" e podemos observar todos os parâmetros que o compõe, ou seja, tudo aquilo que pode ser preenchido para envio ao servidor, ademais dos botões de submissão.
Vá para o navegador e inspecione a caixa de busca da Google e os botões de busca e "Estou com sorte". Você observará que cada "campo" do formulário é uma tag "input". O atributo "type", define se será oculto ("hidden"), texto ("text") ou botão de submissão ("submit"). Por sua vez, o atributo "name" dá nome ao campo.
Alguns "inputs" já contêm valores (no atributo "values"). No nosso exemplo, os botões e campos ocultos. Estes últimos jáidentificaram o idioma ("hl") e o enconding ("ie") com o qual trabalhamos. Ou seja, o **Google já deixou preenchidas partes do formulário**!!. É por esta razão que recebemos resultados preferencialmente em português e relacionados a sites brasileiros!
O que nos interesse preencher, obviamente, é o "input" chamado "q". Em várias ferramentas de busca, "q" (acronismo para "query") é a caixa de texto onde fazemos a busca.
Vamos, então, preencher o campo "q" com a função _set\_values_:
```{r}
google_form <- set_values(google_form,
'q' = "merenda")
```
Simples, não? Colocamos o objeto do formulário no primeiro parâmetro da função e os campos a serem preenchidos na sequência, tal como no exemplo.
Reexamine agora o formulário. Você verá que "q" está preenchido:
```{r}
google_form
```
Legal! Agora vamos fazer a submissão do formulário. No buscador da Google, há duas possibilidades de submissão. Vamos usar "Pesquisa Google" e não "Estou com sorte". Na _submit\_form_, precismos informar a sessão que criamos (conexão com o servidor), o formulário que vamos submeter e o nome do botão de submissão.
Foi por isso, desde o início, que criamos a session! O argumento principal da função do `rvest` que faz a submissão do formulário requer necessariamente que você informe a session.
Veja o exemplo:
```{r}
google_submission <- submit_form(session = google_session,
form = google_form,
submit = "btnG")
```
Pronto! Fizemos a submissão do formulário. Notou o argumento `submit = "btnG"`? Ele é justamente o valor que estava no atributo `<input submit>` do formulário. Já falamos dele. Dê uma checada. Ele é como se fosse o nosso botão de "OK", que envia a busca. Temos que informar isso! E note que há duas possibilidades de submissão nesse formulário: a "Pesquisa Google", que é a busca tradicional, e a "Estou com Sorte". Essas duas opções também existem no seu navegador.
Como output da submissão, recebemos um resultado, salvo agora no objeto `google_submission`. Mas que objeto é esse? Nos termos da linguagem R, de que classe ele é?
Ora! Vejamos:
```{r}
class(google_submission)
```
Ele é uma session! Tal como também era nosso objeto `google_session`. Isso significa que então nossa relação duradoura com o Google está mantida, nossa conexão está estabelecida. O Google, por meio de cookies e outras informações, têm então memória dos passos anteriores que percorremos até aqui. Sabe que estivemos numa página anterior e que submetemos um termo de busca.
Tudo se passa como se tivessemos digitado algo para pesquisar no google (no caso, "merenda"), e então clicado no botão "Pesquisa Google" ou apertado a tecla Enter. O resultado dessa ação vai ser a navegação até outra página, onde agora estão exibidos os resultados da pesquisa. Você já não está mais na mesma página. **Você navegou com o R**!! E a página que obtivemos está guardada no objeto que resulta da função _submit\_form_, juntamente com as informações sobre sua conexão (afinal, trata-se de uma session).
Veja:
```{r}
read_html(google_submission)
```
Agora basta raspar o resultado como já haviámos feito antes. Como você já sabe, podemos aplicar nossas operações diretamente no objeto que resulta da session, sem a necessidade de utilizar a função `read_html`.
Faça no seu navegados (fora do R) a mesma busca utilizando o Google. Examine a página, inspecione o código fonte. E então, tente entender o código abaixo:
```{r}
nodes_resultados <- html_nodes(google_submission, xpath = "//h3/a")
titulos <- html_text(nodes_resultados)
links <- html_attr(nodes_resultados, name = "href")
links <- paste0("https://www.google.com", links)
```
Os títulos dos resultados de busca estão em tags do tipo h3. E as tags 'a' são "filhas" (child) das tags dos títulos. Já vimos isso antes várias vezes. Então você já sabe o que fazer. Certo? (se ainda tiver dúvidas, volte aos quatro primeiros tutoriais).
Certo... Mas como você deve saber por sua experiência prática com o buscador, os resultados de uma busca no Google não são exibidos numa única página. Há várias páginas de resultado. Temos que clicar em "Mais" (veja no seu navegador).
Inspecione a estrutura esse link, clicando com o botão direito sobre ele e selecionando a opção "Inspecionar" (ou equivalente) em seu navegador. Você vai notar que a tag 'a' desse link traz um atributo "class" com valor igual a "pn". Então este é, aparentemente, o link em que queremos clicar para ir para as próximas páginas, certo?
Vejamos se esse link existe no nosso objeto do R:
```{r}
html_nodes(google_submission, xpath = "//a[@class='pn']")
```
Vixe... não existe! Mas como isso é possível!?
Ocorre que a página que está guardada dentro do nosso objeto `google_submission` não é exatamente idêntica àquela que está no seu navegador. A session aberta entre o Google e o R não é a mesma session entre o Google e seu navegador. Você provavelmente já utilizou o Google várias vezes no seu navegador -- e, em algum lugar do seu computador, há cookies e outros arquivos que registraram parte das interações e opções que você selecionou no passado. E a estrutura HTML gerada pelos resultados da busca no Google varia de acordo com isso.
Mas então como saber onde está o nosso link "Mais", no qual poderíamos clicar para ir para as próximas páginas de resultados?
Uma forma simples de saber é a seguinte.
1. Extraia o conteúdo HTML da página de resultados com a função `read_html`.
2. Usando a função `as.character`, transforme esse objeto (que pertence simultâneamente às classes xml_document e xml_node) num vetor de tipo character
3. Usando a função `writeLines`, salve o conteúdo desse vetor num arquivo de texto com a extensão .html.
4. Abra esse arquivo salvo por você no navegador e inspecione o link "Mais"
Com isso, garantimos que a página inspecionada é mesmo aquela que foi coletada pelo R, usando de nossa session:
```{r}
pagina <- read_html(google_submission)
pagina <- as.character(pagina)
writeLines(pagina, "/users/rogerio/desktop/pagina.html")
```
Inspecionou? Encontrou a tag 'a' que contém o link "Mais"? O atributo "class" dessa tag tem valor igual a "fl" e não "pn", como tínhamos visto antes.
O problema, vejam, é que há muitas tags 'a' com `html @class="fl"`:
```{r}
html_nodes(google_submission, xpath = '//a[@class="fl"]')
```
Qual delas queremos? É melhor dar uma inspecionada novamente e sermos mais específicos.
Veja agora abaixo. Que tal isso?
```{r}
html_nodes(google_submission, xpath = '//td[@class="b"]/a[@class="fl"]')
```
Parece que deu certo. Temos apenas um resultado. Mas como saber, como ter certeza? É só verificar se de fato o conteúdo da tag é a palavra "Mais":
```{r}
link = html_nodes(google_submission, xpath = '//td[@class="b"]/a[@class="fl"]')
html_text(link)
```
Viva! Encontramos o link para ir para a próxima página. Haveria, contudo, várias formas de obter esse mesmo link -- usando tanto XPath como CSS. Você consegue compreeender a linha abaixo, que gera o mesmo resultado?
```{r}
html_nodes(google_submission, xpath = "//span[text()='Mais']/..")
```
Agora temos é que clicar no link e segui-lo, para chegar até a próxima página de resultados. Fazemos isso com a função `follow_link()`:
```{r}
google_submission_page2 <- follow_link(google_submission, xpath = "//span[text()='Mais']/..")
```
Como você pode imaginar, a classe desse objeto é, novamente, uma session:
```{r}
class(google_submission_page2)
```
Se é uma session, continuamos conectados. Mas agora, estamos na página 2. Então podemos coletar os novos resultados:
```{r}
nodes_resultados2 <- html_nodes(google_submission_page2, xpath = "//h3/a")
titulos2 <- html_text(nodes_resultados2)
links2 <- html_attr(nodes_resultados2, name = "href")
links2 <- paste0("https://www.google.com", links)
```
**Você está literalmente navegando na internet com o R**, clicando em links e até mesmo fazendo pesquisa no Google! Lindo, não?
Que tal fazer um loop para coletar as primeiras 10 páginas de resultado então?
```{r}
google_url <- "https://www.google.com"
# Estabelecendo a conexão e coletando a primeira página
google_session <- html_session(google_url)
# Raspando o formulário, retirando-o da lista e preenchendo o campo de busca
google_form <- html_form(google_session)[[1]]
google_form <- set_values(google_form,
'q' = "merenda")
# Submetendo os resultados (usando o botão da "Pesquisa Google", o "btnG")
google_session <- submit_form(session = google_session,
form = google_form,
submit = "btnG")
data_resultados <- data_frame()
for(i in 1:10){
print(i)
# Coletando os nodes dos resultados
nodes_resultados <- html_nodes(google_session, xpath = "//h3/a")
# Raspando títulos e links
titulos <- html_text(nodes_resultados)
links <- html_attr(nodes_resultados, name = "href") %>%
paste0("https://www.google.com", .)
# Compilando os resultados num data frame
data_resultados <- bind_rows(data_resultados,
data_frame(titulos, links))
# Navegando até a próxima página
google_session <- follow_link(google_session, xpath = '//span[text()="Mais"]/..')
# Um tempinho para o navegador respirar, carregar a página (e o Google não nos
# bloquear por excesso de requições)
Sys.sleep(.5)
}
```
Vejamos agora os nossos links coletados das 10 primeiras páginas de resultados do Google:
```{r}
data_resultados
```
## Obtendo informações sobre processos no STF
Diferentemente dos Executivos e Legislativos no Brasil, os órgãos do Judiciário, em diversas esferas, têm avançado bem pouco em transparência e no estabelecimento de política de dados abertos. O STF não é exceção. A despeito do grande número de pesquisa sobre o STF, ainda é preciso raspar os dados diretamente do potal do Tribunal para construir bases de dados sobre processos que lá tramitam.
Vamos rapidamnte ver um exemplo de como obter dados do STF.
O primeiro passo será encarar este formulário [aqui](http://www.stf.jus.br/portal/processo/pesquisarProcesso.asp). Queremos buscar os processos por seu número (afinal de contas, no futuro vamos pegar todos os processos de um determinado tipo de 1 até "n"). O formuláio está logo no centro da página.
Vamos proceder como fizemos no caso do buscador da Google. Começaremos estabelecendo uma sessão (conexão) com o servidor. A seguir, vamos raspar a página que contém o formulário e produzir uma lista de fomulários:
```{r}
stf_url <- "http://www.stf.jus.br/portal/processo/pesquisarProcesso.asp"
stf_session <- html_session(stf_url)
stf_form_list <- html_form(stf_session)
stf_form_list
```
Veja que há três formulários diferentes na página. Como decidir entre eles? Precisamos examinar o código HTML. Em geral, inspecionando o campo da busca já teremos um indicativo de qual é o formulário que nos interessa.
Neste caso, queremos fazer a busca por número de processo e o campo de busca se chama "numero". Qual é o formulário que contém tal informação? O terceiro:
```{r}
stf_form <- stf_form_list[[3]]
stf_form
```
Escolhido o formulário, precisamos preenchê-lo. Aqui nos depararemos com um novo problema: como saber qual campo é de preenchimento obrigatório? Esta informação pode esta até visível na página, e esta será nossa primeira pista. No caso do STF, não está. "dropmsgoption", por exemplo, é um campo obrigatório que ainda não está preenchido no formulário que capturamos. Tentativa e erro é o recurso final e tente se colocar no lugar de quem criou o formulário para preenchê-lo.
Note que o campo "dropmsgoption" é uma tag "select" e não "input". As tags "select" vêm acompanhadas, em geral, de suas opções, que relacionam o texto da opção com seu código. Vejam:
```{r}
stf_form$fields$dropmsgoption
```
No nosso caso, queremos o código "1"!
Vamos, então, preencher os dois parâmetos do formulário. Por uma razão que não convém explicar, vamos omitir na nossa busca o nome do processo (ex: ADI, AC, Pet, etc). Buscaremos apenas o número.
```{r}
stf_form <- set_values(stf_form,
'dropmsgoption' = 1,
'numero' = "500")
stf_form
```
Note agora que o botão de preenchimento do formulário não tem nome. Não tem problema. A função _submit\_form_ é bastante inteligente e procurará o campo de submissão do formulário se você não preenhcer o parâmetro "submit" (e vai apontar o nome dele e m uma mensagem. Da mesma forma, se você escrever um nome inexistente, receberá uma mensagem de erro com todos os nomes possíveis dos campos de submissão.
```{r}
stf_submission <- submit_form(session = stf_session,
form = stf_form)
```
Faça o mesmo processo manualmente. O resultado é uma tabela com os links para todos os diferentes tipos de processos com o número buscado. Podemos extrair a tabela (você já sabe fazer isso):
```{r}
tabela_processos <- html_table(stf_submission)[[1]]
```
E os links dos processos (você também sabe fazer isso). Os links precisarão de um pouco de limpeza e utilizaremos a função _str\_sub_ do pacote _stringr_ para resolver este problema:
```{r}
nodes_links_processos <- html_nodes(stf_submission, xpath = "//table//a")
links_processos <- html_attr(nodes_links_processos, name = "href")
library(stringr)
links_processos <- str_sub(links_processos, 8, str_length(links_processos))
links_processos <- paste0("https://www.stf.jus.br/portal/processo/", links_processos)
```
Vamos adicionar os links à tabela:
```{r}
tabela_processos$links <- links_processos
```
Excelente! Podemos escolher o link de um processo usando a tabela (ADI, por exemplo):
```{r}
link_adi <- tabela_processos$links[str_detect(tabela_processos$Processo, "ADI")]
```
E capturar a tabela com as infomações do processo.
```{r}
pagina_adi <- read_html(link_adi)
lista_tabela_adi <- html_table(pagina_adi, fill = T)
tabela_adi <- lista_tabela_adi[[2]]
```
## Desafio
Organize o código para pegar (em loop) uma sequência de processos (por exemplo, 500 a 509) de um tipo específico (ADI).