Captcha를 사용해서 RPA 봇은 막을 수 있지만, 값싼 노동력을 이용하여 mechanical turk와 같은 서비스를 사용할 경우 우회도 가능하고 RPA 봇에 딥러닝 기법을 적용시켜 엔진을 장착시킬 경우 역시 무력화시킬 수 있다.
캡챠 원본 데이터는 Wilhelmy, Rodrigo & Rosas, Horacio. (2013)에서 다운로드 받을 수 있고, 캐글 CAPTCHA Images Version 2 CAPTCHA Images 데이터를 확인가능하다. 캡챠 원본 데이터를 가지고 작업을 진행한다. 다운로드 받아 압축을 풀어 제대로 가져왔는지 확인해 본다.
먼저 제대로 압축을 풀고 데이터를 준비했는지 magick
팩키지 image_read()
함수로 불러 읽어온다.
원본 이미지 데이터에서 라벨 데이터를 준비한다.
library(glue)
file_names <- list.files("data/captcha_dataset/")
captcha_labels <- str_extract(file_names, "[\\w\\d]+?(?=\\.)")
captcha_df <- tibble(label = captcha_labels,
captcha = glue("data/captcha_dataset/{file_names}"))
captcha_df
# A tibble: 1,070 x 2
label captcha
<chr> <glue>
1 226md data/captcha_dataset/226md.png
2 22d5n data/captcha_dataset/22d5n.png
3 2356g data/captcha_dataset/2356g.png
4 23mdg data/captcha_dataset/23mdg.png
5 23n88 data/captcha_dataset/23n88.png
6 243mm data/captcha_dataset/243mm.png
7 244e2 data/captcha_dataset/244e2.png
8 245y5 data/captcha_dataset/245y5.png
9 24f6w data/captcha_dataset/24f6w.png
10 24pew data/captcha_dataset/24pew.png
# … with 1,060 more rows
CNN 신경망 모형을 개발하여 챕챠 이미지를 제대로 학습했는지 훈련/시험 데이터를 통해 확인한다.
randomized_character <- function(label_string) {
string_characters <- str_split(label_string, "") %>% unlist
random_character <- sample(string_characters, 1)
character_pos <- which(string_characters == random_character)
string_characters[character_pos] <- sample(LETTERS, 1)
output_string <- str_flatten(string_characters)
return(output_string)
}
# for(i in 1:10) { randomized_character("ywn6f") }
captcha_trained <- captcha_df %>%
mutate(answer = rbinom(nrow(captcha_df), 1, prob=0.9)) %>%
mutate(predicted = ifelse(answer == 1, label, map_chr(label, randomized_character)))
captcha_trained
# A tibble: 1,070 x 4
label captcha answer predicted
<chr> <glue> <int> <chr>
1 226md data/captcha_dataset/226md.png 1 226md
2 22d5n data/captcha_dataset/22d5n.png 1 22d5n
3 2356g data/captcha_dataset/2356g.png 1 2356g
4 23mdg data/captcha_dataset/23mdg.png 1 23mdg
5 23n88 data/captcha_dataset/23n88.png 1 23n88
6 243mm data/captcha_dataset/243mm.png 1 243mm
7 244e2 data/captcha_dataset/244e2.png 1 244e2
8 245y5 data/captcha_dataset/245y5.png 0 24DyD
9 24f6w data/captcha_dataset/24f6w.png 1 24f6w
10 24pew data/captcha_dataset/24pew.png 1 24pew
# … with 1,060 more rows
캡챠 데이터를 trelliscopejs
를 사용해서 직관적으로 살펴볼 수 있도록 준비한다.
tesseract
모형tesseract
팩키지 ocr()
함수를 사용해서 captcha를 깨보자. 이미지 전처리 작업을 수행하고 나서, tesseract
화이트리스트를 정의한 후에 이를 ocr()
함수에 넣어 텍스트를 추출한다.
library(magick)
library(tesseract)
alphabet <- paste(letters, collapse="")
whitelist <- glue::glue("1234567890{alphabet}")
break_captcha <- function(image) {
captcha_orig <- image_read(image) # 226md
img_processed <- captcha_orig %>%
image_convert(colorspace = 'gray') %>%
image_threshold(threshold = "50%", type = "white")
captcha_text <- tesseract::ocr(img_processed, engine = tesseract(language = "eng",
options = list(tessedit_char_whitelist = whitelist)))
return(captcha_text)
}
break_captcha("data/captcha_dataset/23n88.png")
[1] "723n83\n"
captcha_df <- captcha_df %>%
mutate(text = map_chr(captcha, break_captcha)) %>%
mutate(text = str_remove(text, "\n")) %>%
mutate(matching = ifelse(label == text, 1, 0))
captcha_df %>%
summarise(accuracy = mean(matching))
# A tibble: 1 x 1
accuracy
<dbl>
1 0.0467
잘 추출된 captcha 이미지를 시각적으로 살펴보자
library(slickR)
broken_captcha <- captcha_df %>%
filter(matching == 1)
captcha_num <- htmlwidgets::JS("function(slick,index) {
return '<a>'+(index+1)+'</a>';
}")
captcha_opts <- settings(
dots = TRUE,
initialSlide = 0,
slidesToShow = 10,
slidesToScroll = 10,
focusOnSelect = TRUE,
customPaging = captcha_num,
arrows = FALSE)
slickR(obj = broken_captcha$captcha, height = 100, width = "100%") %synch%
( slickR(broken_captcha$text, slideType = 'p') + captcha_opts )
실패한 captcha 이미지는 많기 때문에 일부 추출하여 원인 파악에 사용한다.
library(slickR)
failed_captcha <- captcha_df %>%
filter(matching == 0) %>%
sample_n(100)
slickR(obj = failed_captcha$captcha, height = 100, width = "100%") %synch%
( slickR(failed_captcha$text, slideType = 'p') + captcha_opts )
1. Wilhelmy R, Rosas H. Captcha dataset. 2013.