Como quebrar
captcha
@brunomacabeusbr
#pylestras
autor
Macabeus
captcha?
Usados por alguns sites para dificultar a ação de robôs
motivação
Eu preciso preencher vários formulários de forma automática e um captcha está me atrapalhando
ferramentas
Python3
Tesseract
OpenCV
estudo de caso
Como estudo de caso, usarei o captcha do site do Tribunal Superior Eleitoral
1º Passo: F5
2º Passo: Ruídos
img = cv.morphologyEx(img, cv.MORPH_CLOSE, np.ones((3, 3), np.uint8))
3º Passo: Preto e branco
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
img = cv.cvtColor(img, cv.COLOR_GRAY2BGR)
for i in img:
for i2 in i:
if (np.array([230, 230, 230]) >= i2).any():
i2[...] = 0
else:
i2[...] = 255
4º Passo: Reconhecer as regiões
4.1º Passo: Apagar os ruídos
im2, contours, hierarchy =\
cv.findContours(
cv.cvtColor(img, cv.COLOR_BGR2GRAY), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE
)
for i in contours:
(x, y), radius = cv.minEnclosingCircle(i)
if radius <= 6:
cv.drawContours(img, [i], -1, (255, 255, 255), -1)
4.2º Passo: Isolar as letras
letters = []
for i2 in contours:
(x, y), radius = cv.minEnclosingCircle(i2)
if radius > 16 and radius < 30:
center = (int(x), int(y))
radius_int = int(radius + 15)
x_min = x - radius_int
y_min = y - radius_int
if x_min < 0:
x_min = 0
if y_min < 0:
y_min = 0
letters.append((x, img[y_min : y + radius_int, x_min : x + radius_int]))
letters_out = []
if len(letters) > 0:
loop = 0
text = ''
for i in letters:
current_letter = i[1]
# Salvar para tesseraczar
cv.imwrite('letter' + str(loop) + '.png', current_letter)
# Pegar o valor ASCII da letra
new_char = rotate('letter' + str(loop) + '.png')[0]
if len(new_char) and new_char[0] != ' ':
text += new_char[0]
else:
text += '?'
loop += 1
letters_out.append((i[0], new_char[0]))
letters_out = sorted(letters_out)
letters_only = [i[1] for i in letters_out]
solution = ''.join(letters_only), title=file_name)
5º Passo: Girar as letras para ler com o Tesseract e usar a resposta com mais confiança
import pyslibtesseract
tesseract_config =\
pyslibtesseract.TesseractConfig(psm=pyslibtesseract.PageSegMode.PSM_SINGLE_CHAR)
tesseract_config.add_variable('tessedit_char_whitelist', 'QWERTYUIOPASDFGHJKLZXCVBNM')
def rotate(file_name):
img = cv.imread(file_name)
rows, cols = img.shape[:2]
most_confidence = [' ', 0]
again = False
for i in range(-1, 2):
M = cv.getRotationMatrix2D((cols/2,rows/2), 10 * i, 1)
dst = cv.warpAffine(img,M,(cols,rows))
letter_height, letter_width = dst.shape[:2]
mask = np.zeros((letter_height + 2, letter_width + 2), np.uint8)
mask[:] = 0
for h in range(letter_height):
cv.floodFill(dst, mask, (letter_width - 1, h), (255, 255, 255), upDiff=(200, 200, 200))
cv.floodFill(dst, mask, (0, h), (255, 255, 255), upDiff=(200, 200, 200))
for w in range(letter_width):
cv.floodFill(dst, mask, (w, 0), (255, 255, 255), upDiff=(200, 200, 200))
cv.floodFill(dst, mask, (w, letter_height - 1), (255, 255, 255), upDiff=(200, 200, 200))
cv.imwrite(str(i) + file_name, dst)
#print(str(i) + file_name)
x = pyslibtesseract.LibTesseract.read_and_get_confidence_char(tesseract_config, str(i) + file_name)
if len(x) == 0:
continue
new_char = x[0]
if most_confidence[1] - 3 <= new_char[1] <= most_confidence[1] + 3:
again = False
else:
again = True
if new_char[0] != ' ' and most_confidence[1] < new_char[1]:
most_confidence[0] = new_char[0]
most_confidence[1] = new_char[1]
#print(new_char)
#print('--------------------------------')
if most_confidence[1] < 60 or again:
for i in range(-5, 6):
M = cv.getRotationMatrix2D((cols/2,rows/2), 10 * i, 1)
dst = cv.warpAffine(img,M,(cols,rows))
letter_height, letter_width = dst.shape[:2]
mask = np.zeros((letter_height + 2, letter_width + 2), np.uint8)
mask[:] = 0
for h in range(letter_height):
cv.floodFill(dst, mask, (letter_width - 1, h), (255, 255, 255), upDiff=(200, 200, 200))
cv.floodFill(dst, mask, (0, h), (255, 255, 255), upDiff=(200, 200, 200))
for w in range(letter_width):
cv.floodFill(dst, mask, (w, 0), (255, 255, 255), upDiff=(200, 200, 200))
cv.floodFill(dst, mask, (w, letter_height - 1), (255, 255, 255), upDiff=(200, 200, 200))
cv.imwrite(str(i) + file_name, dst)
#print(str(i) + file_name)
x = pyslibtesseract.LibTesseract.read_and_get_confidence_char(tesseract_config, str(i) + file_name)
if len(x) == 0:
continue
new_char = x[0]
if new_char[0] != ' ' and most_confidence[1] < new_char[1]:
most_confidence[0] = new_char[0]
most_confidence[1] = new_char[1]
#print(new_char)
#print('--------------------------------')
return most_confidence
-10 graus
[(' ', 1.4195556640625)]
0 graus
[('W', 54.763671875)]
+10 graus
[('N', 77.95476531982422), ('M', 70.48933410644531)]
6º Passo? Histogramar?
Há casos que seria útil histogramar, para dividir a imagem de acordo com as cores, assim separando as letras coladas
Mas isso não resolveria casos com letras coladas e das mesmas cores
Como não ajudaria lá tanto, decidi simplificar o código e não usar histograma
Após vários testes, obtive uma taxa de sucesso de uns 35%
Antes de submeter o formulário, em várias vezes da para saber se houve sucesso em decifrar o captcha ou não, pois basta verificar se reconheceu 5 letras. Se não tiver reconhecido 5 letras, nem chega a submeter o formulário, assim diminui a taxa de erros submetidos.
Logo, obteve-se sucesso no estudo de caso
Conclusão do estudo de caso
trabalhos futuros
Whois do registro.br
Captcha da sepro
reCAPTCHA
Captcha do site hedgewars
além disso...
Há sites (russos) que vendem serviço de quebra de captcha
Muito obrigado
Como quebrar captcha
By brunomacabeus
Como quebrar captcha
- 1,501