6.3 Pacote decryptr

No meu último post anunciei que começaríamos uma série sobre CAPTCHAs. Uma da nossas iniciativas principais nesse tema é a criação do pacote decryptr. Hoje veremos como usar algumas das funções principais desse pacote.

6.3.1 Suposições do decryptr

Ao criar o decryptr reduzimos um pouco o escopo de CAPTCHAs que gostaríamos de incluir. Fizemos isso para não ficarmos malucos, pois existem diversos tipos de testes disponíveis na web!

As suposições são:

  1. Apenas imagens jpg ou png.
  2. Uma imagem possui apenas números e letras.
  3. A quantidade de caracteres de um CAPTCHA é fixa.
  4. Dois CAPTCHAs de mesma origem têm sempre as mesmas dimensões.
  5. Não conseguimos nem queremos quebrar o reCAPTCHA.

6.3.2 Instalação

O decryptr ainda não está no CRAN. Isso significa que para instalá-lo você precisará do devtools:

devtools::install_github('decryptr/decryptr')

As funções principais do decryptr são

  • download_captcha(): baixar imagens da web.
  • read_captcha(): adiciona metadados úteis a uma string com o caminho do CAPTCHA.
  • load_captcha(): carrega a imagem na memória.
  • plot.captcha(): método S3 para desenhar o CAPTCHA na tela.
  • classify(): método S3 para classificar CAPTCHAs manualmente.
  • load_model(): carrega um modelo já ajustado e guardado no pacote decryptrModels
  • train_model(): método S3 para ajustar um modelo para os CAPTCHAs.
  • decrypt(): método S3 para classificar um CAPTCHA a partir de um modelo ajustado e um caminho de imagem.

6.3.3 Fluxo de utilização

O modo de uso planejado do decryptr está descrito na Figura 6.2.

Figura 6.2: Fluxo de utilização do pacote decryptr.

6.3.4 Download

A função download_captcha() tem cinco parâmetros:

  • url= o link do CAPTCHA que queremos baixar.
  • n= a quantidade de CAPTCHAs a serem baixados.
  • path= a pasta que queremos salvar a imagem.
  • secure= se TRUE, fará o download com a opção ssl_verifypeer = FALSE (veja esse post)
  • ext= extensão do arquivo (jpg/jpeg ou png).

Essa não é uma das funções mais seguras do mundo, já que dependemos de uma boa conexão com o servidor de onde os CAPTCHAs serão baixados. A função também não trata de problemas com bloqueio de IP.

Para facilitar a utilização do decryptr, adicionamos algumas atalhos do tipo download_captcha("nome"), que já contêm os padrões para download de alguns sites específicos:

Exemplo:

library(decryptr)
# salva arquivo em ./img/tjmg/captcha<id>.jpeg
arq <- download_captcha("tjmg", n = 1, path = 'imgs/tjmg') 
arq

6.3.5 Visualização

Para plotar um CAPTCHA basta ler o arquivo com read_captcha() e depois usar a função plot(). Exemplo:

library(decryptr)
'imgs/tjmg/captcha4bfc85b5532.jpeg' %>% 
  read_captcha() %>% 
  plot()
CAPTCHA do TJMG.

Figura 6.3: CAPTCHA do TJMG.

Vale mencionar que esse não é um ggplot(), então nem tente somar layers!

6.3.6 Classificação

A classificação manual de CAPTCHAs é importante para possibilitar o treino de modelos preditivos. Para classificar um CAPTCHA você pode utilizar a função classify(), assim:

'imgs/tjmg/captcha4bfc85b5532.jpeg' %>% 
  classify()
Classificando CAPTCHA do TJMG.

Figura 6.4: Classificando CAPTCHA do TJMG.

#> Answer:
#> [1] "imgs/tjmg/captcha4bfc85b5532_.jpeg"

Essa função fará duas coisas:

  • Plota o CAPTCHA na tela.
  • Abre um console para o usuário digitar o valor do CAPTCHA manualmente.

Ao escrever o valor o CAPTCHA, pressione <enter>. Após isso, a função classify() irá adicionar sua classificação após o nome da imagem, como no exemplo acima: _92522. A função classify() gera uma cópia para que seja impossível de perder a imagem original.

Algumas opções do classify():

  • answers= adicionar uma resposta ao invés de esperar abrir o console. Essa opção é útil quando as classficações são feitas automaticamente (e.g., por um quebrador de CAPTCHAs que usa o áudio no lugar da imagem.)
  • path= colocar uma pasta para classificar os CAPTCHAs. Por padrão é a pasta onde os originais estão.

6.3.7 Carregar modelo

A função load_model() é responsável por carregar modelos pré treinados

modelo <- decryptr::load_model("tjmg")
modelo$model
#> Model
#> ___________________________________________________________________________
#> Layer (type)                     Output Shape                  Param #     
#> ===========================================================================
#> conv2d_4 (Conv2D)                (None, 40, 110, 4)            104         
#> ___________________________________________________________________________
#> max_pooling2d_4 (MaxPooling2D)   (None, 20, 55, 4)             0           
#> ___________________________________________________________________________
#> conv2d_5 (Conv2D)                (None, 20, 55, 16)            1616        
#> ___________________________________________________________________________
#> max_pooling2d_5 (MaxPooling2D)   (None, 10, 27, 16)            0           
#> ___________________________________________________________________________
#> conv2d_6 (Conv2D)                (None, 10, 27, 32)            12832       
#> ___________________________________________________________________________
#> max_pooling2d_6 (MaxPooling2D)   (None, 5, 13, 32)             0           
#> ___________________________________________________________________________
#> flatten_2 (Flatten)              (None, 2080)                  0           
#> ___________________________________________________________________________
#> dense_3 (Dense)                  (None, 16)                    33296       
#> ___________________________________________________________________________
#> dropout_2 (Dropout)              (None, 16)                    0           
#> ___________________________________________________________________________
#> dense_4 (Dense)                  (None, 50)                    850         
#> ___________________________________________________________________________
#> reshape_2 (Reshape)              (None, 5, 10)                 0           
#> ___________________________________________________________________________
#> activation_2 (Activation)        (None, 5, 10)                 0           
#> ===========================================================================
#> Total params: 48,698
#> Trainable params: 48,698
#> Non-trainable params: 0
#> ___________________________________________________________________________

6.3.8 Quebrar captcha

A função decrypt quebra o captcha a partir de uma imagem e um modelo.

decrypt('imgs/tjmg/captcha4bfc85b5532.jpeg', modelo)
#> [1] "24485"

Você também pode chamar decrypt com o nome do modelo no lugar do próprio modelo carregado, mas isso é ineficiente

Exercícios

  1. Baixe 1 captcha para cada origem disponível no decryptr. Algum deles não funciona?
  2. Desenhe esses captchas. Algum deles não funciona?
  3. Quebre esse captcha usando decrypt. Algum deles não funciona?