PDF e OCR

Por Julio 28/05/2017

Já precisou extrair dados de arquivos pdf? Bom, eu já. Eu trabalho com jurimetria e preciso extrair dados de diários oficiais, 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.frames 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(stringr)
library(pdftools)
pdf <- '2017-05-27-ocr/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 Execu...

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 ainda não transforma em HTML nem 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. 
  # não sei se funciona em 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 rvest:

library(rvest)
html <- pdf_html(pdf)
html %>% 
  read_html() %>% 
  html_nodes('div') %>% 
  head()
## {xml_nodeset (6)}
## [1] <div id="page1-div" style="position:relative;width:1263px;height:892 ...
## [2] <div id="page2-div" style="position:relative;width:1263px;height:892 ...
## [3] <div id="page3-div" style="position:relative;width:1263px;height:892 ...
## [4] <div id="page4-div" style="position:relative;width:1263px;height:892 ...
## [5] <div id="page5-div" style="position:relative;width:1263px;height:892 ...
## [6] <div id="page6-div" style="position:relative;width:1263px;height:892 ...

PDF para tabelas

Use o tabulizer! Apesar de depender do odiado 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 a função abjutils::rm_accent() para tirar os acentos do texto.

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('2017-05-27-ocr/pdf_compras.pdf')

Essa função serve para arrumar os nomes zoados que vêm no arquivo:

arrumar_nomes <- function(x) {
  x %>% 
    tolower() %>% 
    str_trim() %>% 
    str_replace_all('[[:space:]]+', '_') %>% 
    str_replace_all('%', 'p') %>% 
    str_replace_all('r\\$', '') %>% 
    abjutils::rm_accent()
}

Agora veja a magia do tidyverse posta em prática:

tab_tidy <- tab %>% 
  # transforma matrizes em tibbles
  map(as_tibble) %>% 
  # empilha
  bind_rows() %>% 
  # arruma nomes a partir da primeira linha
  set_names(arrumar_nomes(.[1,])) %>%
  # tira primeira linha
  slice(-1) %>% 
  # tira espaços extras
  mutate_all(funs(str_replace_all(., '[[:space:]]+', ' '))) %>% 
  # tira espaços nas bordas
  mutate_all(str_trim) 

A Tabela 1 mostra as primeiras cinco linhas do resultado.

Table 1: Base arrumada a partir de arquivo pdf, usando o pacote tabulizer.
uf municipios_atendidos tipo subtipo nome_do_empreendimento p_de_execucao total_pac__milhoes orgao
BA ILHÉUS/BA Aeroporto Terminal de Passageiros Aeroporto de Ilhéus - PROJETO DE INFRAESTRUTURA E IMPLANTAÇÃO DO MOP Menor que 50% 2,1 Empresa Brasileira de Infraestrutura Aeroportuária
PR LONDRINA/PR Aeroporto Terminal de Passageiros Aeroporto de Londrina - IMPLANTAÇÃO DO MÓDULO OPERACIONAL - MOP NO PROCESSAMENTO DE EMBARQUE Maior que 50% 4,0 Empresa Brasileira de Infraestrutura Aeroportuária
PA MARABÁ/PA Aeroporto Terminal de Passageiros Aeroporto de Marabá - REFORMA COM AMPLIAÇÃO DO TPS EXISTENTE Maior que 50% 7,1 Empresa Brasileira de Infraestrutura Aeroportuária
CE ACOPIARA/CE Centro de Artes e Esportes Unificados Modelo 3000m² Praças - Acopiara - CE - Modelo 3000m² Menor que 50% 2,0 Ministério da Cultura
SP AMERICANA/SP Centro de Artes e Esportes Unificados Modelo 3000m² Praças - Americana - SP - Modelo 3000m² Menor que 50% 2,4 Ministério da Cultura

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 instalar o tesseract no Windows, basta rodar

install.packages('tesseract')

Para Mac e Linux, siga as instruções dessa página.

A principal função do pacote tesseract é a ocr(). Seu input é o caminho de uma imagem (pdf, jpeg, tiff, entre outras) e seu output é um texto. Logo, nosso primeiro passo é transformar o pdf em imagem.

pdf <- '2017-05-27-ocr/pdf_digitalizado.pdf'
img <- pdf_render_page(
  pdf = pdf,    # caminho do arquivo
  page = 1,     # índice da página
  dpi = 300     # resolução (pontos por polegada)
)

# salvando imagem num arquivo png
png::writePNG(img, '2017-05-27-ocr/pdf_digitalizado_img.png')

Se o PDF tiver mais páginas, você pode fazer um loop para salvar várias imagens. Agora, usamos a função ocr() no arquivo salvo.

library(tesseract)
txt <- ocr('2017-05-27-ocr/pdf_digitalizado_img.png')

# 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, use pdftools::pdf_render_page(), depois png::writePNG() e por fim tesseract::ocr().

É isso. Happy coding ;)

comments powered by Disqus