brcrimR

Por Fernando 13/09/2017

Em maio deste ano, escrevi um post sobre web scraping dos dados da secretaria de segurança pública de São Paulo. Como o título indica, o foco do texto é mostrar como se raspa a página de estatísticas da SSP, mas, mais do que isso, o texto também sugere um roteiro de construção de web scrapers.

Neste post, venho divulgar uma expansão do conteúdo do post passado. Agora é possível acessar os dados da SSP diretamente no R usando o pacote brcrimR, mas a ideia é que no futuro todas as informações divulgadas por alguma Secretaria de Segurança fiquem disponíveis diretamente no R!

devtools::install_github("abjur/brcrimR")

O brmcrimR se propõe a resolver três problemas:

  1. Obter informações criminais brasileiras diretamente no R - Muitas análises interessantes seriam viabilizadas se fosse fácil e rápido carregar informações criminais históricas num data_frame. Fazer isso é a motivação principal do brmcrimR.
  2. Consolidar tabelas em bases históricas - Assim como em São Paulo, muitas Secretarias de Segurança disponibilizam as informações filtradas por mês ou localidade. A segunda motivação principal do brcrimR é iterar por essas páginas.
  3. Padronização - O objetivo menos direto do brcrimR é padronizar as informações disponibilizadas. Esse não é um problema simplesmente computacional, mas algumas rotinas de pré-processamento podem ajudar no processo.

Para ilustrar o funcionamento do brcrimR, vamos olhar o que já está implementado em São Paulo.

Informações agregadas

As tabelas de informações agregadas podem ser obtidas seguindo os passos que descrevi aqui, mas a função brmcrimR::get_summarized_table_sp faz todo o trabalho por nós.

brcrimR::get_summarized_table_sp(year = '2016', city = '1') %>% 
  knitr::kable(caption = "Contagem de boletins de ocorrência na cidade de Amparo.")
Table 1: Contagem de boletins de ocorrência na cidade de Amparo.
Natureza Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez Total municipio ano
HOMICÍDIO DOLOSO (2) 0 0 0 0 0 0 0 0 0 1 0 0 1 1 2016
Nº DE VÍTIMAS EM HOMICÍDIO DOLOSO (3) 0 0 0 0 0 0 0 0 0 1 0 0 1 1 2016
HOMICÍDIO DOLOSO POR ACIDENTE DE TRÂNSITO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
Nº DE VÍTIMAS EM HOMICÍDIO DOLOSO POR ACIDENTE DE TRÂNSITO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
HOMICÍDIO CULPOSO POR ACIDENTE DE TRÂNSITO 0 0 0 1 0 0 1 0 0 0 0 0 2 1 2016
HOMICÍDIO CULPOSO OUTROS 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
TENTATIVA DE HOMICÍDIO 0 0 1 0 0 0 0 0 0 1 0 3 5 1 2016
LESÃO CORPORAL SEGUIDA DE MORTE 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
LESÃO CORPORAL DOLOSA 4 19 13 13 12 15 15 8 16 23 23 10 171 1 2016
LESÃO CORPORAL CULPOSA POR ACIDENTE DE TRÂNSITO 10 18 21 22 13 15 18 10 17 15 15 17 191 1 2016
LESÃO CORPORAL CULPOSA - OUTRAS 1 1 2 1 0 3 0 0 0 0 0 1 9 1 2016
LATROCÍNIO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
Nº DE VÍTIMAS EM LATROCÍNIO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
ESTUPRO (4) 2 0 0 1 0 1 0 1 0 1 0 0 6 1 2016
ESTUPRO DE VULNERÁVEL 0 0 0 0 0 0 0 0 0 1 0 0 1 1 2016
ROUBO - OUTROS (1) 1 0 0 0 1 0 0 1 0 0 0 1 4 1 2016
ROUBO DE VEÍCULO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
ROUBO A BANCO 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
ROUBO DE CARGA 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2016
FURTO - OUTROS 17 19 20 22 13 11 11 12 23 27 17 30 222 1 2016
FURTO DE VEÍCULO 0 1 1 1 5 1 2 1 0 1 2 1 16 1 2016

Para obter os dados históricos, basta usar a função brcrimR::get_historical_summarized_table_sp. Ela funciona da mesma maneira que brcrimR::get_summarized_table_sp, mas pode receber vetores como input. Nesse caso, ela organiza os parâmetros num grid e retorna uma tabela com todas as requisições empilhadas.

brcrimR::get_historical_summarized_table_sp(
  y = c('2016', '2017'), c = '1', ty = 'ctl00$conteudo$btnMensal') %>% 
  filter(Natureza == "LESÃO CORPORAL CULPOSA POR ACIDENTE DE TRÂNSITO") %>% 
  set_names(c('Natureza', 1:12, "Total", "municipio", "ano")) %>% 
  gather(mes, valor, -municipio, -ano, -Natureza, -Total) %>% 
  filter(!is.na(valor)) %>% 
  mutate(data_bo = lubridate::dmy(paste("01", mes, ano, sep = "-"))) %>% 
  ggplot(aes(x = data_bo, y = valor)) +
  geom_bar(stat = 'identity', fill = 'royalblue') +
  theme_minimal(15) +
  labs(x = 'Mês', y = "Número de BO's")

Informações desagregadas

Além dos dados agregados, a partir do ano passado a SSP de São Paulo também passou a divulgar informações detalhadas sobre os BO’s da capital no portal da trasparência. O José de Jesus começou o scraping desses conteúdos e eu só encapsulei tudo dentro de um pacote. Vejam só:

brcrimR::get_detailed_table_sp(folder = 'btnHomicicio', year = '2017', month = '1', department = '0') %>%
  select(NUM_BO, BO_INICIADO, DATAOCORRENCIA, BO_AUTORIA, FLAGRANTE, LATITUDE, LONGITUDE) %>% 
  distinct(NUM_BO, .keep_all = T) %>% 
  head(10) %>% 
  knitr::kable(caption = "Algumas colunas de dez BO's da tabela de boletins de ocorrência de homicídio de janeiro de 2017.")
Table 2: Algumas colunas de dez BO’s da tabela de boletins de ocorrência de homicídio de janeiro de 2017.
NUM_BO BO_INICIADO DATAOCORRENCIA BO_AUTORIA FLAGRANTE LATITUDE LONGITUDE
11589 31/12/2016 22:02:52 31/12/2016 Conhecida Não -23,6027829499999 -46,516050348
1761 31/12/2016 21:02:50 31/12/2016 Conhecida Não -22,7974702349999 -45,1786399879999
2915 31/12/2016 23:33:16 31/12/2016 Conhecida Sim
3 01/01/2017 03:45:42 31/12/2016 Conhecida Não -23,4663377281984 -47,4644919148778
2 01/01/2017 03:40:13 01/01/2017 Desconhecida Não -23,7062770598301 -46,5997084663396
6 01/01/2017 04:25:12 01/01/2017 Desconhecida Não -23,435339469 -45,0776321386071
1 01/01/2017 02:30:11 31/12/2016 Conhecida Sim -23,838385412 -46,5778088709999
4 01/01/2017 04:53:21 01/01/2017 Desconhecida Não -23,6528390081698 -46,4471844195849
859 31/12/2016 21:35:30 31/12/2016 Conhecida Não -23,6027829499999 -46,516050348
13933 31/12/2016 21:09:59 31/12/2016 Conhecida Sim -23,6221113323333 -46,4778365256666

É fantástico que a gente tenha acesso a informações tão detalhadas como latitude e longitude de um crime, mas o formato não é lá essas coisas. Como os dados da SSP provavelmente estão armazenados em um banco de dados relacional, a tabela que baixamos parece ser um inner_join de várias tabelas do banco, pois existem repetições da chave primária NUM_BO. É claro que quem tem um pouco de experiência com esse tipo de coisa vai tirar de letra, mas esse certamente não é o melhor formato para a população em geral.

De toda forma, mesmo nesse formato, é interessante loopar por todas as páginas rapidamente. Por isso, também implementamos a função get_detailed_table_sp, que funciona mais ou menos da mesma forma que a get_historical_summarized_table_sp.

brcrimR::get_historical_detailed_table_sp(f = 'btnHomicicio', y = '2017', m = 1:8, d = '0')

Próximos passos

Encerro aqui a apresentação do pacote, com os seus objetivos e funcionalidades básicas. Ele está longe de ser ideal e tem uma listinha de coisas que queremos implementar no futuro, mas como se trata de dados abertos, não vejo porque não contar com a comunidade para isso! Seguem abaixo algumas ideias:

  • Helper functions para os parâmetros das funções de get de São Paulo. Precisa existir uma função que pegue uma especificação de parâmetro do tipo “Homicídio” e transforme em “btnHomicicio”, que é o parâmetro que precisamos passar pro site do tribunal.
  • Um “desacoplador” de tabelas do portal da transparência.
  • Implementações de funções parecidas para outros estados.

Por hoje é isso, pessoal. Happy coding!

comments powered by Disqus