Cómo encontramos ofertas en MiGuru

    Sabemos que buscar ofertas laborales en cada uno de los portales más populares puede tornarse repetitivo, mecánico y tedioso, ya que todos tienen diferentes mañas a la hora de buscar y filtrar.

    Por eso, uno de nuestros objetivos nucleares en MiGuru es simplificar el proceso de búsqueda, para que puedas hacerlo desde un solo lugar y con la misma interfaz. A continuación, te contamos cómo consolidamos distintos portales en una sola plataforma, desde la integración, hasta que encuentras una oferta perfecta para ti y envías tu postulación.

    Elegir un portal nuevo 👀

    El primer paso del proceso consiste en observar el tipo y cantidad de ofertas que dispone el portal bajo análisis. En general, solemos priorizar la implementación de sitios con mayor flujo de ofertas, como Computrabajo o Laborum, que suelen agregar cientos o miles de vacantes diarias. Sin embargo, hay job boards de nicho, como lo son Get On Board para tecnología, o Pegas Con Sentido para empresas de índole social, que también nos interesan por la calidad y relevancia de sus ofertas.

    OpcionEmpleo.cl es un portal que aún no implementamos

    En el ejemplo de la foto, si buscamos por el título "abogado", obtenemos la friolera de 165 resultados, varios de ellos de hace un día. Da la impresión que es un portal de bastante flujo... Sin embargo, cuando entramos a ver el detalle algunas ofertas, nos damos cuenta que en realidad este sitio solo actúa como intermediario de otros. En la siguiente foto, vemos que la primera oferta en verdad viene de Kit Empleo, un portal para el cual ya hicimos este análisis y pasamos a la fase de implementación.

    Mira la fuente de la oferta marcada con rojo, es Kit Empleo. Ya lo tenemos implementado! 😌

    Como no queremos tener muchas ofertas duplicadas (lo que solo se traduce en ruido para nuestros usuarios), en este caso preferimos no pasar a la siguiente fase.

    Implementar un crawler y un scraper 🤖

    Si encontramos un portal con suficiente tráfico, que aporte ofertas nuevas (i.e. que no haga "eco" de otros sitios), o bien que tenga vacantes de nicho y alta calidad, entonces pasamos a la etapa de implementación.

    Acá es donde usamos dos términos de la jerga computina: crawler y scraper. El primero viene del inglés to crawl, que se traduce como gatear. De la misma forma que una guagua llega a los lugares más sorprendentes gateando, la idea es que este pedazo de software escanee meticulosamente el sitio desde el cual queremos obtener ofertas y postular, para luego presentarlas al segundo proceso, el scraper.

    Un crawler es como un bebé: debería mirar por todas partes. Fotografía por A. Zhenina / Unsplash

    El origen del término scraper quizás no hace tanto sentido (si sabes, porfa cuéntanos!), pero en inglés, to scrape significa raspar. Probablemente se asocie con raspar o quitar lo innecesario de una página web para dejar lo esencial (y luego almacenarlo).

    Parece que en este hilo de Twitter tampoco tienen idea...

    La mayoría de las plataformas de empleo se estructuran con dos funciones claramente diferenciadas: un buscador (como Google), que entrega títulos de oferta y un poco más de información, como el nombre de la empresa o la ubicación del puesto de trabajo y, por separado, una vista con el detalle de la oferta, con los requisitos del cargo y el sueldo. Por lo anterior, la mayoría de nuestros crawlers simulan a un usuario haciendo búsquedas y recopilan solamente los links a las ofertas que aparezcan como resultados. Por otra parte, los scrapers son un poco más elaborados, ya que visitan las URLs encontradas por los crawlers, leen la información del detalle en el formato específico de la página y la transforman en un esquema común para todas las ofertas en MiGuru.

    Comparación de la normalización que intenta lograr un scraper en una oferta para abogados en Laborum.cl (a la izquierda) y en Trabajando.cl (a la derecha). Haz clic en la imagen si quieres verla más grande.

    Como somos fans de Python, tanto crawlers como scrapers los construimos con las librerías requests o httpx para hacer las solicitudes HTTP, y BeautifulSoup para parsear el contenido HTML de los sitios. Algunos usan APIs en formato JSON, lo que nos ahorra bastante juego con selectores que, por lo demás, se pueden romper fácilmente si deciden darle un nuevo look al portal.

    Hasta el minuto, no nos hemos visto obligados a usar Selenium o Scrapy, pero no descartamos usar esas librerías más potentes para portales con mucho procesamiento desde el lado del cliente. Lo bueno de las librerías que usamos es que son bastante rápidas, ya que simplemente parsean texto y no requieren renderizar estilos o interpretar JavaScript.

    Revisar periódicamente el portal ⏰

    Ya estamos casi terminando! Solo falta que agendemos una visita del crawler al portal cada unas cuantas horas para no perder ninguna oferta interesante, y de alguna forma avisarle al scraper que tiene trabajo por hacer cuando el crawler ha encontrado vacantes nuevas.

    Para este propósito, nos mantenemos fieles al ecosistema Python y usamos el orquestador de trabajos distribuidos Celery. Esta librería tiene la gracia que puede enviar trabajos de crawling o scraping a máquinas físicamente distintas, permitiendo distribuir la carga entre ellas. Por el momento, con una sola instancia t3.small en AWS hemos aguantado bien, pero apenas necesitemos monitorear ofertas en muchos más portales (como de otros países por ejemplo 😏), escalar horizontalmente va a ser esperemos trivial.

    Celery nos permite agendar tareas recurrentes à la crontab, además soporta lógicas para reintentar una tarea fallada, esperar cada vez más entre reintentos (como exponential backoff) y se puede conectar una interfaz web bastante útil para monitorear el progreso, las tareas completadas y sus resultados.

    Prestar atención a las fallas 🔥

    Lamentablemente, los scrapers son extremadamente propensos a romperse, ya que para funcionar, normalmente se basan en el layout del sitio e instruyen a la librería BeautifulSoup a que retorne, por ejemplo, todo el texto que esté dentro de un <div> con una clase específica, y que venga seguido por otro <span>. Basta que los desarrolladores del portal cambien un poco el look y nuestro scraper estrella probablemente fallará.

    Por lo anterior, en MiGuru tenemos mecanismos de alerta para cuando un portal tiene una tasa de fallas excesivamente alta. En algún momento consideramos enviar una alerta por Slack, pero la verdad es que es súper común que los portales fallen con errores de servidor (estado 500) o que se interrumpan las conexiones, entonces quizás sería una fuente de alto spam.

    Hoy usamos Sentry para alertarnos de alguna falla recurrente en el proceso de encontrar o descargar ofertas. Tiene la gracia de que agrupa los errores que considera son reincidencias, así no nos muestra 42 veces el mismo JSONDecodeError. Además, cuando cree que no es un one-off error, entonces gatilla un mensaje que nos llega a Slack y así podemos incluirlo en la priorización para arreglarlo.

    Essa fofura é minha filha de 7 meses. Temos um home studio e adoro fotografar crianças, principalmente essa modelo. Crianças e bebês são onde eu encontro os melhores cliques, porque são espontâneos e sempre lindos :)
    Queremos que te relajes mientras MiGuru hace la pega! (V. Zoncoll / Unsplash)

    Víctor Tirreau

    Víctor Tirreau

    Apasionado por la tecnología, IA, sistemas recomendadores y procesamiento de lenguaje natural. Co-fundador de MiGuru y amante del desafío de causar un impacto positivo en la empleabilidad.