Workshop: Web Scraping 2Workshop: Web Scraping 2 Abril, 2020 Apresentação 2 / 74 Linha do tempo 3...

Post on 26-Sep-2020

0 views 0 download

Transcript of Workshop: Web Scraping 2Workshop: Web Scraping 2 Abril, 2020 Apresentação 2 / 74 Linha do tempo 3...

Workshop: Web Scraping 2

Abril, 2020

Apresentação

2 / 74

Linha do tempo

3 / 74

Nossos cursos

4 / 74

Este cursoHTML + CSS + XPath

Iteração + tratamento de erros + agendamento

Paralelização + futuros

Selenium + WebDriver + PhantomJS

SSL + Viewstate + ...

Exercícios variados no estilo MUY:

1. (eu) Conceitos/explicações2. (nós) Exemplo3. (vocês!) Exercício

5 / 74

XPath

6 / 74

Introdução ao HTML

HTML (Hypertext Markup Language) é uma linguagem de markup cujo uso é acriação de páginas web. Por trás de todo site há pelo menos um arquivo .html

7 / 74

Introdução ao HTML

Todo arquivo HTML pode ser dividido em seções que de�nirão diferentesaspectos da página: head são "metadados", enquanto body é o corpo da página

8 / 74

Introdução ao HTML

Tags (head, body, h1, p, ...) demarcam as seções e sub-seções, enquanto atributos(charset, style, ...) mudam como essas seções são renderizadas pelo navegador

9 / 74

Introdução ao HTMLTodo HTML se transforma em um DOM (document object model) dentro donavegador.

Um DOM pode ser representado como uma árvore em que cada node é:

ou um atributoou um textoou uma tagou um comentário

Utiliza-se a relação de pai/�lho/irmão entre os nós.

Para descrever a estrutura de um DOM, usa-se uma linguagem de markupchamada XML (Extensible Markup Language) que de�ne regras para acodi�cação de um documento.

10 / 74

Introdução ao HTML

11 / 74

Introdução ao HTML

12 / 74

XPath - XML Path LanguageExemplo: coletando todas as tags <p> (parágrafos)

library(xml2)

# Ler o HTMLhtml <- read_html("static/html_exemplo.html")

# Coletar todos os nodes com a tag <p>nodes <- xml_find_all(html, "//p")

# Extrair o texto contido em cada um dos nodestext <- xml_text(nodes)text

#> [1] "Sou um parágrafo!" "Sou um parágrafo azul."

13 / 74

XPath - XML Path LanguageCom xml_attrs() podemos extrair todos os atributos de um node:

xml_attrs(nodes)

#> [[1]]#> named character(0)#> #> [[2]]#> style #> "color: blue;"

xml_attr(nodes, "style")

#> [1] NA "color: blue;"

14 / 74

XPath - XML Path LanguageJá com xml_children(), xml_parents() e xml_siblings() podemos acessar aestrutura de parentesco dos nós:

heads <- xml_find_all(html, "head")xml_siblings(heads)

#> {xml_nodeset (1)}#> [1] <body>\n <h1>Título Grande</h1>\n \n <h2>Título um pouco menor</ ...

xml_children(heads)

#> {xml_nodeset (3)}#> [1] <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n#> [2] <meta charset="latin1">\n#> [3] <title>Título da abinha do navegador</title>

15 / 74

CSSCSS (Cascading Style Sheets) descrevem como os elementos HTML devem seapresentar na tela. Ele é responsável pela aparência da página.

<p style='color: blue;'>Sou um parágrafo azul.</p>

O atributo style é uma das maneiras de mexer na aparência utilizando CSS. Noexemplo,

color é uma property do CSS eblue é um value do CSS.

Para associar esses pares properties/values aos elementos de um DOM, existeuma ferramenta chamada CSS selectors. Assim como fazemos com XML,podemos usar esses seletores (através do pacote rvest) para extrair os nós deuma página HTML.

16 / 74

CSSAbaixo vemos um .html e um .css que é usado para estilizar o primeiro. Se osnós indicados forem encontrados pelos seletores do CSS, então eles sofrerão asmudanças indicadas.

17 / 74

Seletores CSS vs. XPathA grande vantagem do XPath é permitir que acessemos os �lhos, pais e irmãosde um nó. De fato os seletores CSS são mais simples, mas eles também são maislimitados.

O bom é que se tivermos os seletores CSS, podemos transformá-los sem muitadi�culdade em um query XPath:

Seletor de tag: p = //pSeletor de classe: .azul = //*[@class='azul']Seletor de id: #meu-p-favorito = //*[@id='meu-p-favorito']

Além disso, a maior parte das ferramentas que utilizaremos ao longo do processotrabalham preferencialmente com XPath.

18 / 74

Seletores CSS vs. XPathhtml <- read_html("static/html_exemplo_css_a_parte.html")xml_find_all(html, "//p")

#> {xml_nodeset (3)}#> [1] <p>Sou um parágrafo normal.</p>#> [2] <p class="azul">Sou um parágrafo azul.</p>#> [3] <p id="meu-p-favorito" class="azul">Sou um parágrafo azul e negrito.</p>

xml_find_all(html, "//*[@class='azul']")

#> {xml_nodeset (2)}#> [1] <p class="azul">Sou um parágrafo azul.</p>#> [2] <p id="meu-p-favorito" class="azul">Sou um parágrafo azul e negrito.</p>

19 / 74

Seletores CSS vs. XPathrvest::html_nodes(html, ".azul")

#> {xml_nodeset (2)}#> [1] <p class="azul">Sou um parágrafo azul.</p>#> [2] <p id="meu-p-favorito" class="azul">Sou um parágrafo azul e negrito.</p>

Note que //p indica que estamos fazendo uma busca na tag p, enquanto //*indica que estamos fazendo uma busca em qualquer tag.

20 / 74

Exercício (eu)Acesse o site de buscas DuckDuckGo.com. Baixe a página de buscas. Dica: use afunção httr::GET().

library(httr)GET("https://duckduckgo.com")

#> Response [https://duckduckgo.com/]#> Date: 2020-04-26 20:45#> Status: 200#> Content-Type: text/html; charset=UTF-8#> Size: 5.42 kB#> <!DOCTYPE html>#> <!--[if IEMobile 7 ]> <html lang="en_US" class="no-js iem7"> <![endif]-->#> <!--[if lt IE 7]> <html class="ie6 lt-ie10 lt-ie9 lt-ie8 lt-ie7 no-js" lang="...#> <!--[if IE 7]> <html class="ie7 lt-ie10 lt-ie9 lt-ie8 no-js" lang="en_US">...#> <!--[if IE 8]> <html class="ie8 lt-ie10 lt-ie9 no-js" lang="en_US"> <![end...#> <!--[if IE 9]> <html class="ie9 lt-ie10 no-js" lang="en_US"> <![endif]-->#> <!--[if (gte IE 9)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js...#> 21 / 74

Exercício (nós)Examine o código-fonte da página para encontrar o elemento correspondente àcaixa de busca e copie o seu XPath pelo navegador. Esse XPath é apropriado? Porque?

//*[@id="search_form_input_homepage"]

Uma forma mais simples talvez fosse

//input[@name="q"]

22 / 74

Exercício (vocês)Examine a aba de rede do inspetor do seu navegador. Quando você faz uma busca,qual requisição corresponde à mesma? Reproduza essa requisição com o pacotehttr. Dica: use o parâmetro query para enviar a requisição correta.

GET("https://duckduckgo.com", query = list(q = "R", t = "h_"))

#> Response [https://duckduckgo.com/?q=R&t=h_]#> Date: 2020-04-26 20:45#> Status: 200#> Content-Type: text/html; charset=UTF-8#> Size: 26.2 kB

23 / 74

Iteração

24 / 74

O fluxo do web scrapingSempre que fazemos um web scraper é bom seguir um �uxo de�nido

Por enquanto já foram apresentados elementos da maior parte do passo-a-passo, mas nada foi dito sobre a iteração

25 / 74

Por que iterar?Di�cilmente queremos fazer uma tarefa de web scraping uma vez só (senãobastaria baixar a página uma vez e raspá-la)

Podemos querer baixar muitas páginas de uma vez ou uma página a cada certotempo

Iteração, tratamento de erros e automatização passam a ser relevantes

O pacote purrr nos ajudará a iterar

O pacote purrr retornará para tratar qualquer erro que possa aparecer

O pacote cronR nos ajudará a agendar a execução de scripts

Se você estiver interessado em aprender mais, veja nosso curso de Deploy

26 / 74

IterarIteração é um padrão de programação extremamente comum que pode seraltamente abreviado

nums <- 1:10resp <- c()for (i in seq_along(nums)) { resp <- c(resp, nums[i] + 1)}resp

#> [1] 2 3 4 5 6 7 8 9 10 11

library(purrr)map_dbl(nums, ~.x + 1)

#> [1] 2 3 4 5 6 7 8 9 10 11

27 / 74

A função mapA função map() recebe um vetor ou uma lista de entrada e aplica uma funçãoem cada elemento do mesmo

Podemos especi�car o formato da saída com a família de funções map_***()

A função pode ser declarada externamente, internamente ou através de umlambda

soma_um <- function(x) { x + 1}

map(nums, soma_um)map(nums, function(x) x + 1)map(nums, ~.x + 1)

28 / 74

Utilidade do mapSe tivermos uma lista de URLs, podemos iterar facilmente em todos sem abrirmão da sintaxe maravilhosa do Tidyverse

urls <- c( "https://en.wikipedia.org/wiki/R_language", "https://en.wikipedia.org/wiki/Python_(programming_language)")

urls %>% map(read_html) %>% map(xml_find_first, "//h1") %>% map_chr(xml_text)

#> [1] "R (programming language)" "Python (programming language)"

29 / 74

Tratando problemasAo repetir uma tarefa múltiplas vezes, não podemos garantir que toda execuçãofuncione

O R já possui o try() e o tryCatch(), mas o purrr facilita ainda mais o trabalho

maybe_read_html <- possibly(read_html, NULL)

read_html("https://errado.que")

#> Error in open.connection(x, "rb"): Could not resolve host: errado.que

maybe_read_html("https://errado.que")

#> NULL

30 / 74

AgendamentoInfelizmente o pacote mais comum (cronR) não funciona no Windows, nele énecessário usar o taskscheduleR

library(cronR)cmd <- cron_rscript("CAMINHO PARA SCRIPT")

cron_add(cmd, "daily", "00:00")cron_add(cmd, "daily", "14:20", days_of_week = c(0, 3, 5))cron_add(cmd, "monthly", "10:30", days_of_month = "first")cron_add(cmd, '@reboot')

Também é possível utilizar uma interface interativa no RStudio em Addins >Schedule R scripts

31 / 74

Exercício (eu)Na página da Wikipédia, encontrar o objeto correspondente à tabela lateral deinformações. Pegar apenas os elementos correspondentes a links.

links <- "https://en.wikipedia.org/wiki/R_language" %>% read_html() %>% xml_find_all("//table[@class='infobox vevent']//a")

head(links)

#> {xml_nodeset (6)}#> [1] <a href="/wiki/File:R_logo.svg" class="image"><img alt="R logo.svg" src=" ...#> [2] <a href="/wiki/File:R_Terminal.png" class="image"><img alt="R Terminal.pn ...#> [3] <a href="/wiki/Programming_paradigm" title="Programming paradigm">Paradig ...#> [4] <a href="/wiki/Multi-paradigm_programming_language" class="mw-redirect" t ...#> [5] <a href="/wiki/Array_programming" title="Array programming">Array</a>#> [6] <a href="/wiki/Object-oriented_programming" title="Object-oriented progra ...

32 / 74

Exercício (nós)Extrair todos os URLs dos links e completá-los com o resto do caminho da Wikipédia.Continuar usando apenas pipes.

urls <- "https://en.wikipedia.org/wiki/R_language" %>% read_html() %>% xml_find_all("//table[@class='infobox vevent']//a") %>% xml_attr("href") %>% paste0("https://en.wikipedia.org", .)

head(urls)

#> [1] "https://en.wikipedia.org/wiki/File:R_logo.svg" #> [2] "https://en.wikipedia.org/wiki/File:R_Terminal.png" #> [3] "https://en.wikipedia.org/wiki/Programming_paradigm" #> [4] "https://en.wikipedia.org/wiki/Multi-paradigm_programming_language"#> [5] "https://en.wikipedia.org/wiki/Array_programming" #> [6] "https://en.wikipedia.org/wiki/Object-oriented_programming"

33 / 74

Exercício (vocês)Baixar todas as páginas da Wikipédia. Dicas: use possibly() para impedir errosquando o URL for inválido; procure saber sobre a função map2() para iterar em maisde uma lista; salve os arquivos com GET(..., write_disk(path)).

paths <- paste0(dir, seq_along(urls), ".html")

maybe_get <- function(url, path) { possibly(GET, NULL)(url, write_disk(path))}

out <- map2(urls, paths, maybe_get)length(compact(out))

#> [1] 32

34 / 74

Paralelismo

35 / 74

O que isso significa?Antigamente, computadores eram capazes de executar apenas uma sequênciade comandos por vez

Avanços tecnológicos permitiram que o processador fosse capaz de fazer"malabarismo" com diversos processos

Paralelismo (ou multiprocessamento) chegou apenas com os primeiros dual-core

36 / 74

Em mais detalhesA unidade de processamento central pode ter mais de um núcleo (multicore)

Um processo é composto por uma sequência de comandos ou tarefas

Cada núcleo consegue executar apenas um comando por vez

Os comandos de um processo podem ser interrompidos para que sejamexecutados os de outro (multitasking)

O computador pode executar várias tarefas simultaneamente escalonando oscomandos para seus diferentes núcleos (multithreading)

Muitos computadores possuem núcleos virtuais, permitindo dois comandos porvez em cada núcleo (hyperthreading)

37 / 74

Exemplo mínimoO pacote parallel já vem instalado junto com o R e consegue rodar comandosparalelamente tanto no Windows quanto em outros sistemas. Por padrão, elequebra a tarefa em 2.

library(parallel)library(microbenchmark)

microbenchmark( seq = map_dbl(1:10000, function(x) x + 1), par = mclapply(1:10000, function(x) x + 1))

#> Unit: milliseconds#> expr min lq mean median uq max neval#> seq 5.900142 8.244917 9.494649 8.907254 10.26182 22.03491 100#> par 10.688572 12.740904 15.611041 14.081677 17.12673 51.45454 100

38 / 74

FuturosO pacote future expande o pacote parallel, permitindo o descolamento detarefas da sessão principal

Ele pode operar em 2 níveis: multicore e multissession

Em cima do future, for construído o furrr com o objetivo de emular a sintaxedo purrr para processamento paralelo

Diferentemente do parallel, o future é capaz de descobrir sozinho o númerode núcleos virtuais do computador

library(future)availableCores()

#> system #> 8

39 / 74

Exercício (eu)Estabelecer um plano de execução paralela com a função plan(). Entender adiferença entre todos os planos disponíveis.

plan(multiprocess)

sequential: não executa em paralelo, útil para testes

multicore: mais e�ciente, não funciona no Windows nem dentro do RStudio

multisession: abre novas sessões do R, mais pesado para o computador

multiprocess: escolhe o melhor entre multicore e multisession

40 / 74

Exercício (nós)Criar uma função que retorna o primeiro parágrafo de uma página da Wikipédiadado o �m de seu URL (como "/wiki/R_language"). Dicas: textos são denotados pelatag <p> em HTML; pule o elemento de classe "mw-empty-elt".

download_wiki <- function(url) { url %>% paste0("https://en.wikipedia.org", .) %>% read_html() %>% xml_find_first("//p[not(@class='mw-empty-elt')]") %>% xml_text()}

41 / 74

Exercício (vocês)Executar a função anterior em paralelo para todas as páginas baixadas no exercíciode iteração. Dicas: utilize future_map() do pacote furrr; não se esqueça dopossibly()"!

library(furrr)

prgs <- "https://en.wikipedia.org/wiki/R_language" %>% read_html() %>% xml_find_all("//table[@class='infobox vevent']//a") %>% xml_attr("href") %>% future_map(possibly(download_wiki, ""))

prgs[[3]]

#> [1] "Programming paradigms are a way to classify programming languages based on the

42 / 74

Selenium

43 / 74

O que é Selenium?Selenium é uma ferramenta que permite automatizar um navegador!

Suporta alguns backends diferentes: PhantomJS, Firefox, Chrome, etc.

Diferentemente do web scraping normal, não precisamos nos preocupar comnenhuma requisição HTTP

O Selenium literalmente cria um navegador invisível para o qual você podepassar as ações a serem tomadas

Por ser uma sessão interativa, não há di�culdades em exibir conteúdodinâmico

Não é necessário compreender o networking do site: tudo é headless

44 / 74

Por que não usá-lo sempre?Vantagens:

Fácil de entender

Permite raspar dados dinâmicos

Permite screen shots

Desvantagens:

Lento e de difícil paralelização

Bastante sensível

RSelenium está completamente quebrado

45 / 74

WebDriverNão existe uma diferença real entre "Selenium" e "WebDriver"

O nome correto da ferramenta é Selenium WebDriver

A diferença está no R: pacotes RSelenium e webdriver

RSelenium essencialmente não funciona

webdriver foi feito pela própria RStudio para resolver o problema

O webdriver funciona somente com o PhantomJS, mas isso não énecessariamente um problema

Instalar é fácil, fazer funcionar é mais ainda

46 / 74

PhantomJSO PhantomJS é um navegador headless baseado em JavaScript feitoespeci�camente para interação automatizada com páginas da web

library(webdriver)# webdriver::install_phantomjs()

pjs <- run_phantomjs()pjs

#> $process#> PROCESS 'phantomjs', running, pid 18534.#> #> $port#> [1] 3807

ses <- Session$new(port = pjs$port)

47 / 74

Exemplo mínimoses$go("https://google.com")ses$takeScreenshot(file = arq)

48 / 74

Elementosses$findElement() retorna um elemento da página dado um seletor ou XPathpara o mesmo

É uma função embutida na sessão (assim como takeScreenshot() e go())

elem$click() clica em um elemento, enquanto elem$sendKeys() "envia" umatecla para o elemento

São funções embutidas no elemento retornado por findElement()

A lista key contém uma série de teclas que podem ser enviadas (comoENTER, etc.)

Ao invés de elem$sendKeys() podemos usar elem$setValue() para escreverum texto no elemento caso isso seja possível

49 / 74

Exercício (eu)Encontrar a página de Fundos de Investimento da XP. Criar uma sessão webdriverpara ir até esta página.

xp <- paste0( "https://institucional.xpi.com.br/investimentos/", "fundos-de-investimento", "/lista-de-fundos-de-investimento.aspx")ses$go(xp)ses$takeScreenshot(file = arq)

50 / 74

Exercício (eu)

51 / 74

Exercício (nós)Fazer a sessão webdriver clicar na aba "Internacional" no topo da página.

elem <- ses$findElement(xpath = '//a[@href="#referenciado"]')elem$click()ses$takeScreenshot(file = arq)

52 / 74

Exercício (nós)

53 / 74

Exercício (vocês)Filtrar apenas os fundos de alto risco. Dica: podemos selecionar um elemento deuma lista com as setas do teclado (analisar key) ou podemos obter a estrutura dalista de seleções.

tab <- "//div[@id='tableReferenciadoRisk']"opt <- paste0(tab, "/span/select/option[@value='5']")

elem <- ses$findElement(xpath = tab)elem$click()Sys.sleep(2)elem <- ses$findElement(xpath = opt)elem$click()

ses$takeScreenshot(file = arq)

54 / 74

Exercício (vocês)

55 / 74

Quer mais?O PhantomJS, apesar de muito capaz, ainda não consegue exibir todo oconteúdo dinâmico de uma página

Para solucionar esse problema, é necessário usar o RSelenium com umnavegador de verdade como backend

Nem sempre a instalação do RSelenium funciona e em alguns sistemasoperacionais há outras dependências

A documentação do RSelenium está atrasadas, di�cultando qualquerpesquisa

O método sugerido para utilizar navegadores externos depende do Docker,um programa sem relação com o R

Não use RSelenium caso não seja estritamente necessário!

56 / 74

DemonstraçãoAs funções do RSelenium são parecidas com as do webdriver, mas envolvem ummais esforço

No exemplo abaixo, o RSelenium abre uma aba do Firefox no meu computador eexecuta todos os comandos ao vivo nela

library(RSelenium)drv <- rsDriver(browser = "firefox", verbose = FALSE)

drv$client$navigate("https://google.com")elem <- drv$client$findElement("xpath", "//input[@name='q']")elem$sendKeysToElement(list("ibovespa", key = "enter"))

Sys.sleep(2)drv$client$screenshot(file = arq)

57 / 74

Demonstração

58 / 74

Mas com o webdriver...Note a presença do grá�co interativo na imagem anterior, isso não é possívelcom o webdriver

Pelas limitações do PhantomJS, nem todo elemento dinâmico pode serrenderizado na tela

É possível usar o webdriver com Docker também, mas nesse caso é melhorrecorrer ao RSelenium

ses$go("https://google.com")elem <- ses$findElement(xpath = "//input[@name='q']")elem$sendKeys("ibovespa", key$enter)

Sys.sleep(2)ses$takeScreenshot(file = arq)

59 / 74

Mas com o webdriver...

60 / 74

Miscelânea

61 / 74

O DEJTO Diário Eletrônico da Justiça do Trabalho é publicado (quase) todo dia e contémtodas as movimentações de vários tribunais do trabalho

O nosso objetivo é baixar o PDF do diário para um dia especí�co

62 / 74

A buscaPara buscar os diários de um dia, basta entrar no site e escolher o diacorrespondente

Analisando o POST, vemos que não há muita di�culdade em reproduzir arequisição

63 / 74

Requisição da buscabody <- list( "corpo:formulario:dataIni" = "17/04/2020", "corpo:formulario:dataFim" = "17/04/2020", "corpo:formulario:tipoCaderno" = "", "corpo:formulario:tribunal" = "", "corpo:formulario:ordenacaoPlc" = "", "navDe" = "", "detCorrPlc" = "", "tabCorrPlc" = "", "detCorrPlcPaginado" = "", "exibeEdDocPlc" = "", "indExcDetPlc" = "", "org.apache.myfaces.trinidad.faces.FORM" = "corpo:formulario", "_noJavaScript" = "false", "javax.faces.ViewState" = "!-m1ev0wvfu", "source" = "corpo:formulario:botaoAcaoPesquisar")

64 / 74

Reproduzindo a buscaurl <- "https://dejt.jt.jus.br/dejt/f/n/diariocon"POST(url, body = body)

#> Error in curl::curl_fetch_memory(url, handle = handle): SSL certificate problem: un

A primeira tentativa não funcionou por causa de um erro no certi�cado SSL

SSL é o nome antigo para TLS (Transport Layer Security), uma ferramenta quepermite que exista o HTTPS

HTTPS é a versão secura e criptografada do HTTP, o protocolo da web

Essencialmente, isso quer dizer que a página do DEJT tem vulnerabilidade

65 / 74

Reproduzindo a busca 2resp <- POST( url, body = body, config(ssl_verifypeer = FALSE))length(resp$content)

#> [1] 16945

Apesar de a consulta ter funcionado, o tamanho da resposta (16kB) não está nempróximo do esperado

Isso ocorre porque a página espera um POST do tipo formulário

A única diferença é o formato em que os dados serão enviados ao servidor

66 / 74

Reproduzindo a busca 3resp <- POST( url, body = body, encode = "form", config(ssl_verifypeer = FALSE))length(resp$content)

#> [1] 16945

Ainda sem sucesso, precisamos começar a conferir o formulário

Se sairmos da página e tentarmos copiar o POST de novo, notaremos que oViewstate mudou

67 / 74

ViewstateO JSF ViewState é um campo escondido que carrega consigo informações sobreo estado de uma sessão do navegador

Ele é capaz de indicar para a próxima página acessada o que tinha acontecidoaté aquele momento

No nosso caso o Viewstate é relevante apenas porque muitas páginas dependemdele para funcionar

# Procurando o Viewstate na página anterior à buscaviewstate <- url %>% GET(config(ssl_verifypeer = FALSE)) %>% content() %>% xml_find_first('//input[@name="javax.faces.ViewState"]') %>% xml_attr("value")

68 / 74

Reproduzindo a busca 4body$javax.faces.ViewState <- viewstateresp <- POST( url, body = body, encode = "form", config(ssl_verifypeer = FALSE))length(resp$content)

#> [1] 47284

Agora que a resposta está correta, podemos continuar a raspagem da páginasem mais problemas

Basta identi�car como baixar cada um dos PDFs

69 / 74

Encontrando o PDFAssim como outras páginas feitas com Java, grande parte dos elementosinterativos do DEJT possui um identi�cador único

No nosso caso, precisamos encontrar o ID dos PDFs antes de poder baixá-los

jid <- resp %>% read_html() %>% xml_find_all("//button") %>% xml_attr("onclick") %>% stringr::str_extract("(?<=plcLogicaItens:0:)j_id[0-9]+") %>% extract(!is.na(.))

70 / 74

Requisição do PDFbody2 <- list( "corpo:formulario:dataIni" = "17/04/2020", "corpo:formulario:dataFim" = "17/04/2020", "corpo:formulario:tipoCaderno" = "", "corpo:formulario:tribunal" = "", "corpo:formulario:ordenacaoPlc" = "", "navDe" = "", "detCorrPlc" = "", "tabCorrPlc" = "", "detCorrPlcPaginado" = "", "exibeEdDocPlc" = "", "indExcDetPlc" = "", "org.apache.myfaces.trinidad.faces.FORM" = "corpo:formulario", "_noJavaScript" = "false", "javax.faces.ViewState" = viewstate, "source" = paste0("corpo:formulario:plcLogicaItens:0:", jid))

71 / 74

Baixando o PDFBaixar um PDF funciona da mesma forma que baixar um HTML para o disco docomputador, basta utilizar a função write_disk()

POST( url, body = body2, write_disk(arq, TRUE), config(ssl_verifypeer = FALSE))

#> Response [https://dejt.jt.jus.br/dejt/f/n/diariocon]#> Date: 2020-04-26 20:46#> Status: 200#> Content-Type: application/pdf#> Size: 9.46 MB#> <ON DISK> /home/clente/Downloads/teste.pdf

72 / 74

Fim(Parabéns!)

73 / 74

Feedbackhttps://forms.gle/rPjT9GiY4T5ZFFEE9

74 / 74