Post atualizado! A versão original do post está aqui!
Já precisou extrair dados de arquivos pdf? Bom, eu já. Eu trabalho com jurimetria e preciso extrair dados de diários de justiça, petições, sentenças, então já viu né…
A primeira pergunta que você precisa fazer antes de ler um pdf é: o arquivo é digital ou digitalizado?
- Se for digital, significa que ele pode ser transcrito diretamente para vários formatos: texto, html, xml e até mesmo
data.frame
s diretamente.
Vamos usar esse exemplo de PDF digital
Se estiver no desktop, é possível ver o documento abaixo:
- Se for digitalizado, você precisará passar um algoritmo de OCR (Optical Character Recognition) para extrair os dados. Provavelmente seu output nesse caso será sempre texto.
Vamos usar esse exemplo de PDF digitalizado
Se estiver no desktop, é possível ver o documento abaixo:
Obs: é possível que seu arquivo seja digitalizado, mas já com uma OCR passada no próprio arquivo. Nesse caso, você pode tratar o documento como digital.
Os créditos dos pacotes abaixo vão todos para o Jeroen Ooms, um dos maiores autores de pacotes da comunidade R
nos últimos dez anos. Sou fã desse cara!
Pacote {pdftools}
para PDFs digitais
Para instalar o {pdftools}
no Windows e no Mac, basta rodar
install.packages("pdftools")
Para instalar no Linux, siga as instruções desse link.
PDF para texto
library(tidyverse)
library(pdftools)
pdf <- 'caminho/para/pdf_digital.pdf'
txt <- pdf_text(pdf)
# imprimindo só os 500 primeiros caracteres da primeira página
cat(str_trunc(txt[1], 500))
## TJ/SP - Comarca de São Paulo
## Movimento Judiciário
##
## Referência: Janeiro de 2011
## Foro: ADAMANTINA
## Unidade: 02 CUMULATIVA
## Planilha: CIVEL
##
##
## Dados da Unidade
## 1. Total de feitos em andamento 2756
## 2. Precatórias 6
## 3. Processos
## 3.1 Processos cíveis 2078
## 3.1.1 De Conhecimento 1111
## 3.1.2 De...
PDF para HTML ou XML
Muitas vezes queremos pegar estruturas no texto que dependem da posição dos elementos. Por exemplo, o texto em um PDF pode estar dividido em várias colunas. Para isso, o ideal seria transformar o arquivo em dados semi-estruturados como HTML ou XML, que separam os elementos do conteúdo do PDF em tags.
Infelizmente, o pdftools
não transforma em HTML nem em XML. Para soltar um HTML, vamos montar uma função que chama pdftohtml
do poppler
por command line.
pdf_html <- function(pdf) {
infos <- pdf_info(pdf) # pega infos do pdf
html <- tempfile(fileext = '.html') # cria arquivo temporário
# monta comando a ser executado.
# no windows, você pode instalar o Poppler por aqui:
# https://blog.alivate.com.au/poppler-windows/
command <- sprintf(
'pdftohtml -f 1 -l %s -q -i -s -noframes %s %s',
infos$pages,
normalizePath(pdf),
html
)
system(command) # roda comando e salva
txt <- readr::read_file(html) # lê arquivo salvo
file.remove(html) # remove arquivo temporário
txt
}
Você pode brincar com o HTML usando o pacote xml2
:
library(xml2)
html <- pdf_html(pdf)
html |>
read_html() |>
xml_find_all('//div') |>
head()
## {xml_nodeset (6)}
## [1] <div id="page1-div" style="position:relative;width:1263px;height:892px;"> ...
## [2] <div id="page2-div" style="position:relative;width:1263px;height:892px;"> ...
## [3] <div id="page3-div" style="position:relative;width:1263px;height:892px;"> ...
## [4] <div id="page4-div" style="position:relative;width:1263px;height:892px;"> ...
## [5] <div id="page5-div" style="position:relative;width:1263px;height:892px;"> ...
## [6] <div id="page6-div" style="position:relative;width:1263px;height:892px;"> ...
PDF para tabelas
Use o {tabulizer}
! Apesar de depender do polêmico {rJava}
(que é um pacote chato de instalar e configurar) o {tabulizer}
é capaz de extrair os dados diretamente para tabelas, de forma simples e intuitiva.
Para instalar o {tabulizer}
, siga as instruções dessa página. Já adianto que pode não ser uma tarefa fácil, principalmente por conta do {rJava}
.
Exemplo: Uma vez montei esse código para estruturar um pdf contendo gastos em obras públicas. Além de usar o {tabulizer}
, usei os pacotes usuais do {tidyverse}
e o {janitor}
para arrumar os nomes das colunas.
library(tabulizer)
Vamos usar esse pdf de exemplo.
Se estiver no desktop, é possível ver o documento abaixo:
# No meu pc demorou 40 segundos.
tab <- extract_tables('caminho/para/pdf_compras.pdf')
Agora veja a magia do {tidyverse}
e do pacote {janitor}
posta em prática:
tab_tidy <- tab |>
# transforma matrizes em tibbles
map(as_tibble) |>
# empilha
bind_rows() |>
# arruma nomes a partir da primeira linha
janitor::row_to_names(1) |>
janitor::clean_names() |>
# tira espaços extras
mutate(across(everything(), str_squish))
A tabela abaixo mostra as primeiras cinco linhas do resultado.
Pacote {tesseract}
para PDFs digitalizados
O {tesseract}
é uma biblioteca escrita em C
e é uma das mais famosas ferramentas abertas para extração de textos a partir de imagens. O pacote em R
de mesmo nome serve para usar essa biblioteca pelo R
sem causar dores de cabeça.
Para nossa felicidade, hoje em dia os pacotes {pdftools}
e {tesseract}
estão integrados. Dessa forma, podemos utilizar a função pdftools::pdf_text_ocr()
para extrair o texto de um PDF usando OCR.
Vamos usar esse pdf de exemplo.
Se estiver no computador, é possível ver o documento abaixo:
pdf <- 'caminho/para/pdf_digitalizado.pdf'
txt <- pdf_ocr_text(
pdf = pdf, # caminho do arquivo
page = 1 # índice da página
)
## Converting page 1 to pdf_digitalizado_1.png... done!
Se o PDF tiver mais páginas, basta colocar os índices no texto.
# imprimindo só os 300 primeiros caracteres do resultado
cat(str_trunc(txt, 300))
## This is a sample document to test the PDF Image+Text OCR Engine.
## This is a sample document to test the PDF Image+Text OCR Engine.
## This is a sample document to test the PDF Image+Text OCR Engine.
## This is a sample document to test the PDF Image+Text OCR Engine.
## This is a sample document to test the...
Wrap-up
- Se seu pdf for digital, use
pdftools::pdf_text()
. - Se seu pdf for digitalizado,
pdftools::pdf_text_ocr()
, que usa o pacote{tesseract}
por trás. - Existem alternativas úteis, como o Poppler em linha de comando e o pacote
{tabulizer}
.
É isso. Happy coding ;)