Neste terceiro tutorial, eu mostro como extrair dados de páginas web baixadas dos tribunais usando uma ferramenta poderosa como xpath.
Neste tutorial veremos como usar xpath para extrair dados de um html. Ele faz parte de uma série de tutorias voltados à raspagem de dados de tribuanis com R. Assim como expressões regulares, xpath requer tempo para dominá-lo. Para iniciar, falaremos de html, pois ele é a base sobre a qual xpath opera. Veja o exemplo abaixo.
x <- '<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div class="julgado">
<a href="https://link_para_documento"></a>
<div class="processo">1234567-23.2022.8.26.0000</div>
<div class="assunto">Dano moral</div>
<div class="colegiado">
Relator: fulano de tal
<br>
Revisor: Sicrano
<br>
Presidente: Beltrano
</div>
<div class="classe processual">Procedimento Comum Cível</div>
</div>
</body>
</html>'
O exemplo acima, o qual chamaremos de documento, inicia com o elemento ou tag <html> e termina com</html>. Essa é a sintaxe básica. O mesmo elemento que abre, fecha. Por vezes o encerramento é dispensável, quando entre os dois não vai nada. Por exemplo,<br> indica apenas quebra de linha.
Logo após o <html>, há outra tag <head> e dentro desta, outra tag. No mesmo nível do <head>, há a tag <body> e dentro desta pode haver um número indefinido de tags filhas. Toda tag que contêm outras é chamada de tag mãe ou pai e a tag contida chamada de filha. Uma tag pode ser mãe e filha.
Adicionalmente às tags, existem os atributos. Estes qualificam as tags e individualizam a informação. Essa individualização permite que uma outra linguagem, CSS, agrege aspectos estéticos ao documento. Os atributos vêm com um valor. Em um dos exemplos acima, o atributo classe contêm o valor “processo”.
Esses atributos e tags são marcadores sobre os quais navegamos, com a ajuda de xpath, para extrair as informações desejadas.
XPath é uma linguagem de consulta que permite navegar por documentos que usam marcadores, como os arquivos XML e HTML. XPath significa XML Path Language. Para extrar dados de um documento html, você precisa conhecer alguns metacaracteres que lhe permitam navegar. Veja abaixo:
/ indica o nó raiz
// indica um nó em qualquer lugar do documento
. indica o nó atual
.. indica o nó pai do nó atual
/@ indica um atributo
//tag/following-sibling::tag Manda para uma específica no mesmo nível da atual.
//tag/parent::tag Manda para uma tag pai específica.
//* indica qualquer elemento ou atributo
Por exemplo, a expressão XPath /html/body/p
seleciona todos os elementos <p>
que são filhos do elemento <body>
que é filho do elemento <html>
. Esta expressão, por outro lado, indica um caminho absoluto, pois usa barra única. Isso significa que esta ordem é estrita, o primeiro elemento é html, logo abaixo dele tem o body e logo abaixo deste tem o p.
Para indicar caminho relativo, ou seja, procurar o elemento independentemente se ele é filho, neto, bisneto etc, usamos barras duplas //. Por exemplo, se fizermos //p, iremos nos posicionar em todos os elementos p que estejam no mesmo nível daquele foi encontrado pela primeira vez.
Além disso, xpath possui verbos e outros indicadores. Por vezes, o próprio conteúdo pode ser considerado um elemento. Mais adiante, iremos dar exemplos.
O R possui um pacote que permite navegar por html e extrair as informações desejadas. O nome dele é xml2. Vamos trabalhar no exemplo acima que foi associado ao objeto x.
A primeira coisa a fazer é ler o html para o R usando a função read_html(). O objeto x era um mero texto, poderia ser um arquivo html. Ao lê-lo com read_html, convertemos em xml_document. Somente agora podemos aplicar xpath.
doc |>
xml_find_all("/*") |> ### Encontra o elemento
xml_text() |> ## Extrai o texto dentro deste elemento.
cat() ## Usado apenas para uma visualização amigável.
1234567-23.2022.8.26.0000
Dano moral
Relator: fulano de tal
Revisor: Sicrano
Presidente: Beltrano
Procedimento Comum Cível
No exemplo acima, eu usei “/*“, ou seja, posicione no documento inteiro. Depois disso, eu usei xml_text() para extrair todo o conteúdo textual do documento. Usei cat() apenas para uma visualização agradável.
Agora vamos extrair apenas o número do processo:
doc |>
xml_find_all("//div[@class='processo']") |>
xml_text()
[1] "1234567-23.2022.8.26.0000"
Note que eu usei o caminho relativo “//div”, ou seja, saltei diretamente para o primeiro div do documento. No entanto, há mais divs irmãos desse div, então eu preciso informar que quero apenas o div que contenha o processo. Para tanto, uso [@class='processo'], ou seja, vá para a div que contenha o atributo class cujo valor é processo.
Agora vamos pegar o assunto:
doc |>
xml_find_all("//div[@class='assunto']") |>
xml_text()
[1] "Dano moral"
Por vezes, não há um atributo que distinga claramente um conteúdo. Vamos supor que não tenha nenhum atributo indicando o assunto, apenas indicando o processo. Podemos informar ao xpath que queremos o conteúdo do div que vem logo depois do div do processo:
doc |>
xml_find_all("//div[@class='processo']/following-sibling::div[1]") |>
xml_text()
[1] "Dano moral"
Note que eu fui até o div do processo e, em seguida, usei following-sibling::div, ou seja, pegue o irmão seguinte que se chama div.
Agora vamos supor que eu queira todos as categorias, ou seja, os valores dos atributos: processo, assunto, colegiado e classe processual, e não o conteúdo:
doc |>
xml_find_all("//div/div") |>
xml_attr("class")
[1] "processo" "assunto" "colegiado"
[4] "classe processual"
Note que eu fui até o div filho de um div e, em vez de usar xml_text(), usei xml_attr(“class”) para indicar que quero o atributo e não o conteúdo.
Outra maneira de atingir o mesmo objetivo é:
doc |>
xml_find_all("//div/div/@class") |>
xml_text()
[1] "processo" "assunto" "colegiado"
[4] "classe processual"
No exemplo acima, eu converti o atributo em elemento e extraí o conte údo dele com xml_text().
Há situações em que eu quero caminhar para trás. por exemplo, vamos pegar a irmã anterior do assunto, ou seja, processo:
doc |>
xml_find_all("//div[@class='assunto']/preceding-sibling::div") |>
xml_text()
[1] "1234567-23.2022.8.26.0000"
Note que usei preceding-sibling para atingir meu objetivo.
Por vezes queremos obter o conteúdo do pai de um elemento. Por exemplo, podemos extrair o link do inteiro teor desta forma, sem recorrer ao pai:
doc |>
xml_find_all("//div/a") |>
xml_attr("href")
[1] "https://link_para_documento"
Outra maneira de fazer isso, é recorrer ao indicador pai:
doc |>
xml_find_all("//div[@class='processo']/../a") |>
xml_attr("href")
[1] "https://link_para_documento"
Note que eu fui até a div do processo e usei .. (dois pontinhos) para voltar à mãe desse div e caminhar até a tag a.
Outra forma:
doc |>
xml_find_all("//div[@class='processo']/parent::div/a") |>
xml_attr("href")
[1] "https://link_para_documento"
Esta forma é mais precisa, especialmente quando queremos um avô ou bisavô mais distante.
Por fim, vamos dar um exemplo em que queremos extrair apenas o relator, ou seja o primeiro texto do colegiado.
doc |>
xml_find_all("//div[@class='colegiado']/text()[following-sibling::br][1]") |>
xml_text()
[1] "\n Relator: fulano de tal\n "
Veja que eu usei o texto como como tag. Encontrei todo os textos dentro de colegiado seguidos de quebra de linha <br>, mas retive apenas o primeiro.
Se eu quiser o revisor;
doc |>
xml_find_all("//div[@class='colegiado']/text()[following-sibling::br][2]") |>
xml_text()
[1] "\n Revisor: Sicrano\n "
Isso já não funcionaria com o presidente, pois ele não é seguido de br. Para tanto, precido pensar num artifício. Vou até o texto que tem duas quebras de linha antes dele:
doc |>
xml_find_all("//div[@class='colegiado']/text()[preceding-sibling::br][2]") |>
xml_text()
[1] "\n Presidente: Beltrano\n "
Em todos os casos acima, eu usei xml_find_all porque geralmente estou buscando várias ocorrência numa mesma página. No entanto, como havia uma só ocorrência, eu deveria ter usado xml_find_first.
Por fim, nos últimos exemplos, o resultado veio com quebra de linha e espaços extras, eu posso eliminá-los usando o argumento trim = TRUE.
doc |>
xml_find_all("//div[@class='colegiado']/text()[preceding-sibling::br][2]") |>
xml_text()
[1] "\n Presidente: Beltrano\n "
For attribution, please cite this work as
Filho (2023, May 2). Jurimetria: Raspagem nos tribunais - Parte 3: extração com XPATH. Retrieved from https://direitoemdados.consudata.com.br/posts/2023-05-02-extracaocomxpath/
BibTeX citation
@misc{filho2023raspagem, author = {Filho, José de Jesus}, title = {Jurimetria: Raspagem nos tribunais - Parte 3: extração com XPATH}, url = {https://direitoemdados.consudata.com.br/posts/2023-05-02-extracaocomxpath/}, year = {2023} }