El cajón de Drazul

El lugar donde duerme el pequeño dragón

Cómo Saltarse Un Captcha Sencillo

Hace unos meses, durante las tareas rutinarias de mantenimiento de los web scrapers que mantenía en ese momento, me topé con un extraño caso que no venía sino a confirmar la voluntad de transparencia de los gobernantes, a cualquier nivel, de nuestro país.

La tarea que tenía automatizada era la de descargar los boletines oficiales que publica la Comunidad Autónoma de Cataluña y mi sorpresa fue mayúscula cuando vi que habían puesto un captcha para poder descargar estos documentos públicos.

A continuación voy a explicar brevemente, porque no tiene demasiada complejidad, el procedimiento que seguí para poder resolver el captcha de forma automática.

El captcha al que nos enfrentamos es bastante sencillo para lo habitual, por lo que la tarea no se hace demasiado complicada. En la siguiente imagen podemos ver un ejemplo del mismo.

Como podemos ver es una imagen bastante sencilla visualmente y que, a priori, podría reconocer fácilmente un OCR, pero tiene truco: la imagen viene con un fondo transparente.

Visto el inconveniente principal solo queda pasar a realizar una funcion de threshold o, mejor dicho, modificar la imagen para que sea más fácilmente reconocible por un software. Estas técnicas suelen jugar con las combinaciones de colores para sea sencillo el reconocimiento de los bordes y figuras. Para la imagen que tenemos, que solo tiene dos colores (negro de las letras y transparente del fondo), queda pasarlo a los colores que más diferencia tienen entre sí, el blanco y el negro, por lo que vamos a modificar la imagen para que el transparente se convierta en blanco. A continuación pongo un pequeño script en python que realiza esta función.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def threshold(filename):

    img = Image.open(filename)
    img = img.convert('RGBA')
    pixdata = img.load()

    for y in xrange(img.size[1]):
        for x in xrange(img.size[0]):
          # Si tiene el canal alfa a 0 (es un color transparente), cambio el color a blanco
            if pixdata[x, y][3] == 0:
                pixdata[x, y] = (255, 255, 255, 255)

    img.save('threshold_' + filename)
    return img.convert('L')

Una vez que tenemos la imagen preparada solo queda ver cómo reconocer qué caracteres contiene contiene la imagen, por lo que recurrimos a un OCR. Durante el desarrollo hice un set de pruebas con tres OCR libres que se encuentran en el repositorio de Debian: Tesseract, Gocr y Ocrad.

El que mejor resultado me dió fue Tesseract, pero recomiendo probar varios antes de decidirse por uno, ya que siguen en desarrollo y pueden variar enormemente sus porcentajes de aciertos, además que influye mucho en el resultado el tipo de imagen que tenemos, la tipografía, el tamaño, el thresholding de la imagen, …

Comments