Desde aquí puedes ejecutar un ejemplo de scraper con Cython online:
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
ytqdm
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.
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.
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 dere.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
:
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:
Aquí puedes ver un pedazo de código de una cola de llamadas asíncronas con asyncio
y aiohttp
:
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:
Cachea
Cachea todo lo que puedas. Para cachear se puede hacer fácilmente con el siguiente tipo de código:
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.
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.
Creo que este será el futuro de la documentación y los archivos estáticos web como readthedocs se queden como referencias.
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
@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!
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!