Resolver captcha con python, convert y tesseract


Tesseract-ocr-test Los captchas son seguros siempre que no sean resueltos por un automatismo, en ese caso dejan de ser útiles. Tesseract-ocr puede cambiar la utilidad de un captcha en questión de minutos, ya que combinando tesseract con imagemagick es possible resolver captchas débiles. En este articulo describiremos algunos métodos para resolverlos con un automatismo programado en python que realizará diferentes modificaciones con imagemagick para que tesseract-ocr pueda leer de mejor forma el captcha.

Las versiones de los programas utilizados:

  • Python 2.7.13
  • pip 19.0.3 from /usr/local/lib/python2.7/dist-packages/pip (python 2.7)
  • Debian 9.8
  • tesseract 3.04.01 ·· leptonica-1.74.1 ·· libgif 5.1.4 : libjpeg 6b (libjpeg-turbo 1.5.1) : libpng 1.6.28 : libtiff 4.0.8 : zlib 1.2.8 : libwebp 0.5.2 : libopenjp2 2.1.2
  • Version: ImageMagick 6.9.7-4 Q16 x86_64 20170114

Lo primero que necesitaremos es instalar los siguientes paquetes.

apt install imagemagick tesseract-ocr pythoni python-pip
pip install pytesseract
pip install pillow

Antes de empezar es necesario comentar que tanto tesseract como imagemagick tienen muchas opciones y combinaciones entre ellas para modificar la imagen y poder subir bastante el ratio de aciertos en la resolución de los captchas.

Opciones de tesseract

En estos casos en tesseract utilizaremos 2 opciones, el whitelist de carácteres para filtrar por letras minúsculas, mayúsculas y digitos, y como segunda opción el -psm normalmente elegiremos la opción 8 que hace referencia a resolver una sola palabra. Las opciones son las siguientes:

  • 0 = Orientation and script detection (OSD) only.
  • 1 = Automatic page segmentation with OSD.
  • 2 = Automatic page segmentation, but no OSD, or OCR.
  • 3 = Fully automatic page segmentation, but no OSD. (Default)
  • 4 = Assume a single column of text of variable sizes.
  • 5 = Assume a single uniform block of vertically aligned text.
  • 6 = Assume a single uniform block of text.
  • 7 = Treat the image as a single text line.
  • 8 = Treat the image as a single word.
  • 9 = Treat the image as a single word in a circle.
  • 10 = Treat the image as a single character.

Para conocer más parámetros se puede consultar esta web: http://www.sk-spell.sk.cx/tesseract-ocr-parameters-in-302-version

Opciones de imagemagick

En imagemagick utilizaremos diferentes opciones y combinaciones de ellas, las más comunes son las siguientes: - Eliminar un color, en este caso el negro. ( convert image.png -fuzz 10% -fill white -opaque black image.tif ) - Crear negativo de la imagen. ( convert image.png -negate image.tif) - Dilatar el color blanco, es posible indicarle el tipo de dilatación y el tamaño. ( convert image.tif -morphology Dilate Disk:1 image.tif ) - Disminuir el color blanco, es posible indicarle el tipo de disminución y el tamaño. (convert image.tif -morphology Dilate Disk:1 image.tif) - Incrementa y disminuye el umbral a partir de un porcentage. ( convert image.png -threshold 50% image.tif ) - Cambia la saturación de color. ( convert image.png -level 25%,100% image.png )

Mas parámetros en este enlace: http://www.imagemagick.org/Usage/

1 - Captcha con mayúsculas y distorsinado

Captcha1

En este captcha distorsionan las letras, las letras son en un fondo blanco y las letras están en negro. No tiene mayor dificultado ya que modificando los parámetros de tesseract para permitir únicamente mayúsculas y con la opción de una solo palabra (-psm 8 -c tessedit_char_whitelist=ABCDEFGHIJKMNLOPKRSTUVWXYZ )

try:
        from PIL import Image
except ImportError:
        import Image

import pytesseract

captcha = pytesseract.image_to_string(Image.open('captcha1.png'),config='-psm 8 -c tessedit_char_whitelist=ABCDEFGHIJKMNLOPKRSTUVWXYZ')
captcha = captcha.replace(" ", "").strip()
print(captcha)

Al ejecutar el script podemos ver que no tiene más misterio, no es necesario ni modificar la imagen para que tesseract reconozca las letras.

2 - Captcha con dígitos descuadrados

Captcha2

En este caso son números con un fondo blanco, muy sencillo también, en este caso solo utilizaremos dígitos.

try:
        from PIL import Image
except ImportError:
        import Image

import pytesseract
captcha = pytesseract.image_to_string(Image.open('captcha2.jpg'),config='-psm 8 -c tessedit_char_whitelist=0123456789')
captcha = captcha.replace(" ", "").strip()
print(captcha)

En este caso tampoco es necesario modificar la imagen para que tesseract haga su mágia.

3 - Captcha con letras minúsculas y dígitos

Captcha3

Aquí las letras son con un estilo más manuscrito y ya existe una combinación más amplia de dígitos y letras minúsculas, aunque existe un fondo distorsionado podemos ver que las letras están bien diferenciadas del fondo.

try:
        from PIL import Image
except ImportError:
        import Image

import pytesseract
captcha = pytesseract.image_to_string(Image.open('captcha3.png'),config='-psm 8 -c tessedit_char_whitelist=0123456789abcdfghijkmnlopqrsturstuvwxyz')
captcha = captcha.replace(" ", "").strip()
print(captcha)

Vemos que tampoco hace falta retocar la imagen.

4 - Captcha con operación matemática sencilla

Captcha4

Se complica un poco el captcha, ahora si que hay que modificar la imagen y además realizar la suma, la suma no la haremos en el código ya que es sencillo de automatizar para realizarla. La imagen parece que tiene mucho ruido y distorsión pero en realidad los números y símbolos tienen un color concreto que no tiene la distorsión, nosotros aprobecharemos eso y eliminaremos todos los colores menos el de los dígitos y símbolos para facilitar el trabajo a imagemagick.

try:
        from PIL import Image
except ImportError:
        import Image

import pytesseract
os.system("convert captcha4.jpg -fill white -fuzz 10% +opaque '#2820e5' captcha4.tif")
os.system("convert captcha4.tif -morphology Erode Disk:1.5 captcha4.tif")
os.system("convert captcha4.tif -level 70%,100% captcha4.tif")
captcha = pytesseract.image_to_string(Image.open('captcha4.tif'),config='-psm 8 -c tessedit_char_whitelist=\'0123456789=+??\'')
captcha = captcha.replace(" ", "").strip()
print(captcha)

Es necesario modificar la imagen en este caso, primero eliminamos todos los colores excepto el color que nos interesa, para ello tenemos que saber que color es en RGB, podemos saberlo con Gimp o cualquier otro programa de edición de imagenes. En este caso el color es #2820e5. Después también disminuimos el color y creamos una curva de color. El resultado es el siguiente:

Captcha4.2

En tesseract podemos ver que se añaden nuevos carácteres como el de suma o los interrogantes.

5 - Captcha con letras mayúsculas y malla en el fondo

Captcha5

Este captcha tiene un fondo blanco y unos puntos negros que definen el fondo de las letras.

try:
        from PIL import Image
except ImportError:
        import Image

import pytesseract
os.system("convert captcha5.png -morphology Erode Disk:2 captcha5.tif")
os.system("convert captcha5.tif -morphology Dilate Disk:1.5 captcha5.tif")
os.system("convert captcha5.tif -threshold 41% captcha5.tif")
captcha = pytesseract.image_to_string(Image.open('captcha5.tif'),config='-psm 8 -c tessedit_char_whitelist=ABCDEFGHIJKMNLOPKRSTUVWXYZ')
captcha = captcha.replace(" ", "").strip()
print(captcha)

Para sacar el texto primero disminuimos el blanco augmentando los puntos negros, luego volvemos a augmentar el blanco, finalmente disminuimos el umbral para tener un fondo negro bien definido y las letras en blanco. El resultado es el siguiente: Captcha5.2

Conclusión

Un captcha con una generación poco compleja no realizará su función de parar los automatísmos, para poder evitarlos lo mejor será utilizar la mayor cantidad de combinación de carácteres posibles (mayúsculas, minúsculas, dígitos y símbolos). O utilizar sistemas de reconocimiento de imagenes u otro tipo de catpcha donde no se reconozcan carácteres sino que se realizen puzzles, asociaciones,...

Los catpchas con operaciones matemáticas tampoco sirven si no tienen una combinación de colores y distorsiones de letras compleja. Las distorsiones de colores en el fondo no sirven de nada si es posible aislar el color que necesitamos.

Enlaces de interés

https://pypi.org/project/pytesseract/ https://github.com/tesseract-ocr/tesseract/wiki/FAQ http://www.sk-spell.sk.cx/tesseract-ocr-parameters-in-302-version http://www.imagemagick.org/Usage/