Como construir el scraper más rápido usando Python

in #spanish3 years ago (edited)

Desde aquí puedes ejecutar un ejemplo de scraper con Cython online: Binder

Hace ya tiempo que empecé a desarrollar bots que extraen información de la red y siempre me ha obsesionado el hacerlo lo más rápido posible. Así que tras mucho aprendizaje y errores, voy a dejar aquí algunos puntos claves que me hubiera gustado conocer hace un año en el arte de manejar estructuras de datos lo más rápido posible a bajo nivel.

Aquí puedes ver un ejemplo, con sólo Cython, aiohttp y tqdm como dependencias. Todos los ejemplos de código han sido sacados de ese programa. Aviso que este tutorial puede ser complicado de seguir para alguien que no busca otra cosa que aprender lo que pone en el título, así que, vamos allá...


Constrúyete tu la maquinaria

Si quieres tener control con el tiempo de donde saltarán las excepciones tienes que lidiar con todas las que puedas desde el principio, forzándolas a saltar. Para ello es útil desarrollar a la vez que testeamos. A la larga, este sistema es infalible si somos capaces de conocer nuestro programa.

Code 01

Usa expresiones regulares

Mira este archivo, esta plagado de expresiones que parecen incomprendibles. Aquí se encuentra el código que procesa las páginas. Si parseamos el DOM siempre será más lento el proceso de extracción de la información de las páginas, pero usando expresiones regulares se acelera, con la contrapartida de tener que lidiar con las expresiones.

Para tener una referencia de cuanto se puede acelerar te puedo decir que en la versión anterior de ese programa se extraían los datos parseando el DOM con la biblioteca bs4 y había funciones que tardaban más de 3 segundos en ejecutarse, cuando ahora lo hacen en 0.15 segundos, con la ventaja además de no necesitar dependencias externas.

Code 02

Otro punto clave es conocer la velocidad de las funciones. Por ejemplo, si queremos reemplazar cadenas de forma simple debemos usar "cadena".replace("cad", "CAD") en lugar de re.sub(r'cad', "CAD", "cadena") ya que es mucho más rápida. En general siempre es buena idea utilizar las funciones incorporadas al lenguaje antes de tirar de bibliotecas externas.


Ejecuta en C (si puedes) y hazlo asíncrono

Aunque no se gana mucho con peticiones pequeñas ejecutando en C (aunque esto depende de la complejidad de los datos), si los procesamos en C mientras los extraemos de forma asíncrona con aiohttp tendremos un rendimiento más que considerable.

cython

Con Cython podemos mejorar el rendimiento de los bucles en procesos de entrada y salida de datos. Tan sólo con declarar los enteros con cdef int i = 0 y crear bucles con for i in range(datos) el procesador crea bucles de C con tipado estático más veloces que los bucles normales.

Una opción interesante en este tipo de operaciones es prescindir al máximo posible de los condicionales if, y usar try y except, que son más rápidos. El punto es hacerlo como en C, dar por supuesto de que los datos son del tipo correcto y si fallan podemos rescatarlos porque estamos en Python. Imagínate que te viene un dato de tipo float y también puede ser una cadena "?", pero tu quieres el float si no None:

Code 03

asyncio y aiohttp

Con las mejoras introducidas en el módulo asyncio desde Python3.6 podemos crear generadores asíncronos, los cuales son llamados mediante una sintaxis muy interesante:

Code 04

Aquí puedes ver un pedazo de código de una cola de llamadas asíncronas con asyncio y aiohttp:

Code 05

Siempre llevar los tests al momento y bien ordenados soluciona las inconsistencias que pueden salir a medida que crece el código. Cuando madura, si funciona, hay que respetarlo y enfocar los errores desde una perspectiva más amplia. Como herramienta de testing recomiendo pytest porque me aporta mucha libertad.


Espacios de nombres

Usa espacios de nombres. Un truco muy interesante es, cuando tienes una clase en un archivo y en vez de llamar a un método dentro de la clase quieres llamar a un grupo de métodos o a un objeto:

Code 06

Cachea

Cachea todo lo que puedas. Para cachear se puede hacer fácilmente con el siguiente tipo de código:

Code 07

Documenta

Es posible crear la documentación sólo documentando correctamente los docstrings de tus métodos y funciones. Yo uso el paquete sphinx.ext.napoleon que es el que usa Google, pues tiene una sintaxis muy legible e intuitiva en el código fuente. Viene incluido con sphinx así que sólo hemos de incluirlo en la configuración de la documentación. Aquí tienes la guía de estilo de código Python de Google.

RTD

Además de subir la documentación a readthedocs.org (lo cual es muy fácil con un archivo de configuración), puedes alojarla en un notebook en la red con tu programa instalado para que los usuarios puedan aprender como funciona tu programa mientras corres el código de forma interactiva. con Binderhub. Puedes especificar los parámetros de la instalación según su documentación y crear links directos a los archivos de tu repositorio desde la página principal.

Binder

Creo que este será el futuro de la documentación y los archivos estáticos web como readthedocs se queden como referencias.

Sort:  

Excelente publicación, Python es uno de mis lenguajes favoritos, y también creo que cada vez hay mas formas y técnicas de scraping.

Buenas tardes, @mondeja
Vengo a comentarte que estoy montando un proyecto en solitario: un club de talentos con derecho de admisión reservado.
El propósito es que, entre todos, nos ayudemos a crecer en la comunidad y crearnos un hueco en la plataforma con mejores remuneraciones.
Si estás interesado en saber más, accede a mi servidor de Discord y te explico más a fondo en cuanto pueda.
https://discord.gg/E6xkvwJ
Saludos.

Congratulations @mondeja! You have received a personal award!

2 Years on Steemit
Click on the badge to view your Board of Honor.

Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - Play-off for third result


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

@mondeja you were flagged by a worthless gang of trolls, so, I gave you an upvote to counteract it! Enjoy!!

Congratulations @mondeja! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 3 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.17
TRX 0.03
JST 0.043
BTC 10905.32
ETH 380.86
USDT 1.00
SBD 0.98