Cómo extraer datos de LinkedIn: Guía 2025

Aprenda a crear un raspador de LinkedIn basado en Python, a eludir las barreras de inicio de sesión y a extraer datos clave sobre puestos de trabajo para obtener una mejor perspectiva.
26 min de lectura
How to scrape LinkedIn

En esta guía aprenderás:

  • Qué es un raspador de LinkedIn
  • Una comparación entre el scraping web de LinkedIn y la recuperación de datos a través de sus API
  • Cómo evitar el muro de inicio de sesión de LinkedIn
  • Cómo crear un script de scraping de LinkedIn en Python
  • Cómo obtener datos de LinkedIn con una solución más sencilla y eficaz

¡Empecemos!

¿Qué es un raspador de LinkedIn?

Un raspador de LinkedIn es una herramienta que extrae automáticamente datos de las páginas de LinkedIn. Normalmente se centra en páginas populares, como perfiles, ofertas de empleo, páginas de empresas y artículos.

El raspador recopila información clave de esas páginas y la presenta en formatos útiles como CSV o JSON. Estos datos son valiosos para la generación de clientes potenciales, la búsqueda de empleo, el análisis de la competencia y la identificación de tendencias de mercado, entre otros casos de uso.

Scraping web de LinkedIn frente a API de LinkedIn

LinkedIn proporciona una API oficial que permite a los desarrolladores integrarse con la plataforma y recuperar algunos datos. Entonces, ¿por qué deberías considerar el Scraping web de LinkedIn? La respuesta es sencilla y tiene cuatro puntos clave:

  1. La API solo devuelve un subconjunto de datos definido por LinkedIn, que puede ser mucho más pequeño que los datos disponibles a través del Scraping web.
  2. Las API pueden cambiar con el tiempo, lo que limita el control que tienes sobre los datos a los que puedes acceder.
  3. La API de LinkedIn se centra principalmente en integraciones de marketing y ventas, especialmente para usuarios de nivel gratuito.
  4. La API de LinkedIn puede costar decenas de dólares al mes, pero sigue teniendo estrictas limitaciones en cuanto a los datos y el número de perfiles de los que se pueden recuperar datos.

La comparación entre los dos enfoques para obtener datos de LinkedIn da lugar a la siguiente tabla resumen:

Aspecto API de LinkedIn Scraping web de LinkedIn
Disponibilidad de datos Limitada a un subconjunto de datos definido por LinkedIn Acceso a todos los datos disponibles públicamente en el sitio
Control sobre los datos LinkedIn controla los datos proporcionados Control total sobre los datos que recuperas
Enfoque Principalmente para integraciones de marketing y ventas Puede dirigirse a cualquier página de LinkedIn
Coste Puede costar decenas de dólares al mes Sin coste directo (excepto la infraestructura)
Limitaciones Número limitado de perfiles y datos al mes Sin limitaciones estrictas

Para obtener más información, lea nuestra guía sobre Scraping web frente a API.

Qué datos extraer de LinkedIn

A continuación, se incluye una lista parcial de los tipos de datos que se pueden extraer de LinkedIn:

  • Perfil: datos personales, experiencia laboral, formación, contactos, etc.
  • Empresas: información de la empresa, listas de empleados, ofertas de empleo, etc.
  • Ofertas de empleo: descripciones de puestos, solicitudes, criterios, etc.
  • Puestos de trabajo: cargo, empresa, ubicación, salario, etc.
  • Artículos: publicaciones, artículos escritos por usuarios, etc.
  • LinkedIn Learning: cursos, certificaciones, itinerarios formativos, etc.

Cómo evitar el muro de inicio de sesión de LinkedIn

Si intentas visitar la página de LinkedIn Jobs directamente después de una búsqueda en Google en modo incógnito (o sin haber iniciado sesión), esto es lo que deberías ver:

The LinkedIn login wall

La página anterior puede llevarte a creer que la búsqueda de empleo en LinkedIn solo es posible después de iniciar sesión. Dado que extraer datos detrás de un muro de inicio de sesión puede dar lugar a problemas legales, ya que puede violar los términos de servicio de LinkedIn, es mejor evitarlo.

Afortunadamente, existe una solución sencilla para acceder a la página de empleo sin que te bloqueen. Solo tienes que visitar la página de inicio de LinkedIn y hacer clic en la pestaña «Empleos»:

Clicking on the “Jobs” link on LinkedIn’s homepage

Esta vez, obtendrás acceso a la página de búsqueda de empleo:

The unblocked job search page

Como puedes ver en la barra de direcciones de tu navegador, esta vez la URL contiene parámetros de consulta especiales:

https://www.linkedin.com/jobs/search?trk=guest_homepage-basic_guest_nav_menu_jobs&position=1&pageNum=0

En concreto, el argumento trk=guest_homepage-basic_guest_nav_menu_jobs parece ser el factor clave que impide que LinkedIn aplique un muro de inicio de sesión.

Sin embargo, eso no significa que puedas acceder a todos los datos de LinkedIn. Algunas secciones siguen requiriendo que inicies sesión. Sin embargo, como veremos a continuación, eso no supone una limitación importante para el Scraping web de LinkedIn.

Crear un script de scraping web de LinkedIn: guía paso a paso

En esta sección del tutorial, aprenderás a extraer datos de ofertas de empleo para puestos de ingeniero de software en Nueva York de LinkedIn:

Software engineer positions in NY

Comenzaremos desde la página de resultados de búsqueda, recuperaremos automáticamente las URL de las ofertas de empleo y, a continuación, extraeremos los datos de sus páginas de detalles. El rastreador de LinkedIn se escribirá en Python, uno de los mejores lenguajes de programación para el Scraping web.

¡Realicemos el scraping de datos de LinkedIn con Python!

Paso n.º 1: Configuración del proyecto

Antes de empezar, asegúrate de tener Python 3 instalado en tu ordenador. Si no es así, descárgalo y sigue el asistente de instalación.

Ahora, utiliza el siguiente comando para crear una carpeta para tu proyecto de scraping:

mkdir linkedin-raspador

linkedin-scraper representa la carpeta del proyecto de su raspador de LinkedIn en Python.

Entra en ella e inicializa un entorno virtual dentro de ella:

cd linkedin-raspador
python -m venv venv

Cargue la carpeta del proyecto en su IDE de Python favorito. Visual Studio Code con la extensión Python o PyCharm Community Edition serán suficientes.

Crea un archivo raspador.py en la carpeta del proyecto, que debe contener esta estructura de archivos:

The file structure of the LinkedIn Scraper

En este momento, scraper.py es un script Python en blanco, pero pronto contendrá la lógica de scraping deseada.

En la terminal del IDE, activa el entorno virtual. En Linux o macOS, ejecuta este comando:

./env/bin/activate

De forma equivalente, en Windows, ejecuta:

env/Scripts/activate

¡Genial! Ahora ya tienes un entorno Python para el Scraping web.

Paso n.º 2: Selección e instalación de las bibliotecas de scraping

Antes de sumergirte en la programación, debes analizar el sitio de destino para determinar las herramientas de scraping adecuadas para el trabajo.

Comience abriendo la página de búsqueda de LinkedIn Jobs en modo incógnito, tal y como se ha explicado anteriormente. El uso del modo incógnito garantiza que haya cerrado la sesión y que ningún dato almacenado en la caché interfiera en el proceso de scraping.

Esto es lo que debería ver:

Note the two popups on the target page

LinkedIn muestra varias ventanas emergentes en el navegador. Estas pueden resultar molestas cuando se utilizan herramientas de automatización del navegador como Selenium o Playwright.

Afortunadamente, si inspeccionas el código fuente HTML de la página devuelta por el servidor, verás que ya contiene la mayor parte de los datos de la página:

The HTML source code of the target page

Del mismo modo, si comprueba la pestaña «Red» en DevTools, observará que la página no depende de llamadas API dinámicas significativas:

The AJAX calls performed by the page

En otras palabras, la mayor parte del contenido de las páginas de empleo de LinkedIn es estático. Eso significa que no necesitas una herramienta de automatización del navegador para extraer datos de LinkedIn. Una combinación de un cliente HTTP y un analizador HTML será suficiente para recuperar los datos de empleo.

Por lo tanto, utilizaremos dos bibliotecas de Python para extraer los empleos de LinkedIn:

  • Requests: una sencilla biblioteca HTTP para enviar solicitudes GET y recuperar el contenido de páginas web.
  • Beautiful Soup: un potente analizador HTML que facilita la extracción de datos de páginas web.

En un entorno virtual activado, instala ambas bibliotecas con:

pip install requests beautifulsoup4

A continuación, impórtelas en raspador.py con:

from bs4 import BeautifulSoup
import requests

¡Genial! Ahora ya tiene todo lo necesario para empezar a extraer datos de LinkedIn.

Paso n.º 3: Estructurar el script de scraping

Como se explica en la introducción de esta sección, el raspador de LinkedIn realizará dos tareas principales:

  1. Recuperar las URL de las páginas de empleo de la página de búsqueda de LinkedIn Jobs.
  2. Extraer los detalles de cada oferta de empleo específica

Para mantener el script bien organizado, estructura tu archivo scraper.py con dos funciones:

def retrieve_job_urls(job_search_url):
    pass
    # Por implementar...

def scrape_job(job_url):
    pass
    # Por implementar...

# Llamadas a funciones y lógica de exportación de datos...

A continuación se muestra lo que hacen las dos funciones:

  • retrieve_job_urls(job_search_url): Acepta la URL de la página de búsqueda de empleo y devuelve una lista de URL de páginas de empleo.
  • scrape_job(job_url): Acepta una URL de página de empleo y extrae detalles del empleo, como el título, la empresa, la ubicación y la descripción.

A continuación, al final del script, llama a estas funciones e implementa la lógica de exportación de datos para almacenar los datos de empleo extraídos. ¡Es hora de implementar esa lógica!

Paso n.º 4: Conéctese a la página de búsqueda de empleo

En la función retrieve_job_urls(), utiliza la biblioteca requests para obtener la página de destino utilizando la URL pasada como argumento:

response = requests.get(job_url)

Entre bastidores, esto realiza una solicitud HTTP GET a la página de destino y recupera el documento HTML devuelto por el servidor.

Para acceder al contenido HTML de la respuesta, utiliza el atributo .text:

html = response.text

¡Genial! Ahora ya está listo para parseo el HTML y empezar a extraer las URL de los trabajos.

Paso n.º 5: recuperar las URL de los trabajos

Para parsear el HTML recuperado anteriormente, páselo al constructor Beautiful Soup:

soup = BeautifulSoup(html, "html.parser")

El segundo argumento especifica el analizador HTML que se va a utilizar. html.parser es el analizador predeterminado incluido en la biblioteca estándar de Python.

A continuación, inspeccione los elementos de la ficha de empleo en la página de búsqueda de empleo de LinkedIn. Haga clic con el botón derecho del ratón en uno de ellos y seleccione «Inspeccionar» en las herramientas de desarrollo de su navegador:

Inspecting a job card

Como puede ver en el código HTML de la ficha de empleo, las URL de los empleos se pueden extraer utilizando el siguiente selector CSS:

[data-tracking-control-name="public_jobs_jserp-result_search-card"]

Nota: El uso de atributos data-* para la selección de nodos en el Scraping web es ideal, ya que suelen utilizarse para pruebas o seguimiento interno. Eso hace que sea menos probable que cambien con el tiempo.

Ahora, si echas un vistazo a la página, verás que algunas tarjetas de empleo pueden aparecer borrosas detrás de un elemento de invitación para iniciar sesión:

The blurred job cards have the same HTML structure as the non-blurred ones

No hay que preocuparse, ya que se trata solo de un efecto del frontend. El HTML subyacente sigue conteniendo las URL de las páginas de empleo, por lo que puede obtener esas URL sin necesidad de iniciar sesión.

Esta es la lógica para extraer las URL de las ofertas de empleo de la página de LinkedIn Jobs:

job_urls = []

job_url_elements = soup.select("[data-tracking-control-name="public_jobs_jserp-result_search-card"]")
for job_url_element in job_url_elements:
  job_url = job_url_element["href"]
  job_urls.append(job_url) 

select() devuelve todos los elementos que coinciden con el selector CSS dado, que contienen enlaces a ofertas de empleo. A continuación, el script:

  1. Itera a través de estos elementos
  2. Accede al atributo HTML href (la URL de la página del empleo)
  3. Lo añade a la lista job_urls

Si no estás familiarizado con la lógica anterior, lee nuestra guía sobre el Scraping web con Beautiful Soup.

Al final de este paso, tu función retrieve_job_urls() tendrá este aspecto:

def retrieve_job_urls(job_search_url):
    # Realiza una solicitud HTTP GET para obtener el HTML de la página.
    response = requests.get(job_search_url)

    # Accede al HTML y lo analiza.
    html = response.text
    soup = BeautifulSoup(html, "html.parser")

    # Dónde almacenar los datos extraídos
    job_urls = []

    # Lógica de extracción
    job_url_elements = soup.select("[data-tracking-control-name="public_jobs_jserp-result_search-card"]")
    for job_url_element in job_url_elements:
      # Extrae la URL de la página de empleo y añádela a la lista
      job_url = job_url_element["href"]
      job_urls.append(job_url)

    return job_urls

Puedes llamar a esta función en la página de destino como se muestra a continuación:

public_job_search_url = "https://www.linkedin.com/jobs/search?keywords=Software%2BEngineer&location=New%20York%2C%20New%20York%2C%20United%20States&geoId=102571732&trk=public_jobs_jobs-search-bar_search-submit&position=1&pageNum=0"
job_urls = retrieve_job_urls(public_job_search_url)

¡Buen trabajo! Ya has completado la primera tarea de tu raspador de LinkedIn.

Paso n.º 6: Inicializar la tarea de scraping de datos de empleo

Ahora, concéntrate en la función scrape_job(). Al igual que antes, utiliza la biblioteca requests para obtener el HTML de la página de empleo de la URL proporcionada y analízalo con Beautiful Soup:

response = requests.get(job_url)

html = response.text
soup = BeautifulSoup(html, "html.parser")

Dado que el rastreo de datos de empleo en LinkedIn implica la extracción de diversa información, lo dividiremos en dos pasos para simplificar el proceso.

Paso n.º 7: Recuperación de datos de empleo — Parte 1

Antes de lanzarte a extraer datos de LinkedIn, debes inspeccionar una página de detalles de una oferta de empleo para comprender qué datos contiene y cómo recuperarlos.

Para ello, abra una página de oferta de empleo en modo incógnito y utilice DevTools para inspeccionar la página. Céntrese en la sección superior de la página de la oferta de empleo:

The HTML code of the top section of the page

Tenga en cuenta que puede extraer los siguientes datos:

  • El título del puesto de trabajo de la etiqueta <h1>.
  • La empresa que ofrece el puesto del elemento [data-tracking-control-name="public_jobs_topcard-org-name"]
  • La información sobre la ubicación de .topcard__flavor--bullet
  • El número de solicitantes del nodo .num-applicants__caption

En la función scrape_job(), después de analizar el HTML, utilice la siguiente lógica para extraer esos campos:

title_element = soup.select_one("h1")
title = title_element.get_text().strip()

company_element = soup.select_one("[data-tracking-control-name="public_jobs_topcard-org-name"]")
company_name = company_element.get_text().strip()
company_url = company_element["href"]

location_element = soup.select_one(".topcard__flavor--bullet")
location = location_element.get_text().strip()

applicants_element = soup.select_one(".num-applicants__caption")
applicants = applicants_element.get_text().strip()

La función strip() es necesaria para eliminar cualquier espacio inicial o final del texto extraído.

A continuación, céntrate en la sección de salarios de la página:
The HTML code of the salary section

Puede recuperar esta información a través del selector CSS .salary. Dado que no todos los puestos de trabajo tienen esta sección, necesita una lógica adicional para comprobar si el elemento HTML está presente en la página:

salary_element = soup.select_one(".salary")
if salary_element is not None:
    salary = salary_element.get_text().strip()
else:
    salary = None

Cuando .salary no está en la página, select_one() devolverá None, y la variable salary se establecerá en None.

¡Genial! Acabas de extraer parte de los datos de una página de puestos de trabajo de LinkedIn.

Paso n.º 8: Recuperación de datos de empleo — Parte 2

Ahora, concéntrate en la sección inferior de la página de ofertas de empleo de LinkedIn, empezando por la descripción del puesto:

The HTML code of the salary section

Puedes acceder al texto de la descripción del puesto de trabajo desde el elemento .description__text .show-more-less-html utilizando este código:

description_element = soup.select_one(".description__text .show-more-less-html")
description = description_element.get_text().strip()

Por último, la parte más difícil del scraping web de LinkedIn es lidiar con la sección de criterios:

The HTML code of the criteria section

En este caso, no se puede predecir exactamente qué datos aparecerán en la página. Por lo tanto, debe tratar cada entrada de criterios como un par <nombre, valor>. Para extraer los datos de criterios:

  1. Seleccione el elemento <ul> utilizando el selector CSS .description__job-criteria-list li
  2. Itere sobre los elementos seleccionados y, para cada uno de ellos:
    1. Extraiga el nombre del elemento de .description__job-criteria-subheader
    2. Extraiga el valor del elemento de .description__job-criteria-text
    3. Añada los datos extraídos como un diccionario a una matriz

Implementa la lógica de extracción de LinkedIn para la sección de criterios con estas líneas de código:

criteria = []
criteria_elements = soup.select(".description__job-criteria-list li")
for criteria_element in criteria_elements:
    name_element = criteria_element.select_one(".description__job-criteria-subheader")
    name = name_element.get_text().strip()

    value_element = criteria_element.select_one(".description__job-criteria-text")
    value = value_element.get_text().strip()

    criteria.append({
        "name": name,
        "value": value
    })

¡Perfecto! Acabas de extraer con éxito los datos del puesto de trabajo. El siguiente paso es recopilar todos los datos extraídos de LinkedIn en un objeto y devolverlos.

Paso n.º 9: recopilar los datos extraídos

Utiliza los datos extraídos en los dos pasos anteriores para rellenar un objeto de trabajo y devolverlo desde la función:

job = {
    "url": job_url,
    "title": title,
    "company": {
        "name": company_name,
        "url": company_url
    },
    "location": location,
    "applications": applicants,
    "salary": salary,
    "description": description,
    "criteria": criteria
}
return job 

Después de completar los tres pasos anteriores, scrape_job() debería tener este aspecto:

def scrape_job(job_url):
    # Enviar una solicitud HTTP GET para obtener el HTML de la página.
    response = requests.get(job_url)

    # Acceder al texto HTML de la respuesta y analizarlo.
    html = response.text
    soup = BeautifulSoup(html, "html.parser")

    # Lógica de scraping
    title_element = soup.select_one("h1")
    title = title_element.get_text().strip()

    company_element = soup.select_one("[data-tracking-control-name="public_jobs_topcard-org-name"]")
    company_name = company_element.get_text().strip()
    company_url = company_element["href"]

    location_element = soup.select_one(".topcard__flavor--bullet")
    location = location_element.get_text().strip()

    applicants_element = soup.select_one(".num-applicants__caption")
    applicants = applicants_element.get_text().strip()

    elemento_salario = soup.select_one(".salary")
    si elemento_salario no es None:
      salario = elemento_salario.get_text().strip()
    else:
       salario = None

    elemento_descripción = soup.select_one(".description__text .show-more-less-html")
    descripción = description_element.get_text().strip()

    criterios = []
    criteria_elements = soup.select(".description__job-criteria-list li")
    for criteria_element in criteria_elements:
        name_element = criteria_element.select_one(".description__job-criteria-subheader")
        name = name_element.get_text().strip()

        value_element = criteria_element.select_one(".description__job-criteria-text")
        value = value_element.get_text().strip()

        criteria.append({
            "name": name,
            "value": value
        })

    # Recopilar los datos extraídos y devolverlos
    job = {
        "url": job_url,
        "title": title,
        "company": {
            "name": company_name,
            "url": company_url
        },
        "location": location,
        "applications": applicants,
        "salary": salary,
        "description": description,
        "criteria": criteria
    }
    return job

Para recopilar los datos de los puestos de trabajo, llama a esta función iterando sobre las URL de los puestos de trabajo devueltas por retrieve_job_urls(). A continuación, añade los datos recopilados a una matriz de puestos de trabajo:

jobs = []
for job_url in job_urls:
    job = scrape_job(job_url)
    jobs.append(job)

¡Fantástico! La lógica de recopilación de datos de LinkedIn ya está completa.

Paso n.º 10: Exportar a JSON

Los datos de empleo extraídos de LinkedIn ahora se almacenan en una matriz de objetos. Dado que estos objetos no son planos, tiene sentido exportar estos datos en un formato estructurado como JSON.

Python permite exportar datos a JSON sin necesidad de dependencias adicionales. Para ello, puede utilizar la siguiente lógica:

file_name = "jobs.json"
with open(file_name, "w", encoding="utf-8") as file:
    json.dump(jobs, file, indent=4, ensure_ascii=False)

La función open() crea el archivo de salida jobs.json, que luego se rellena con json.dump(). El indent=4 garantiza que el JSON tenga un formato legible, y ensure_ascii=False garantiza que los caracteres no ASCII se codifiquen correctamente.

Para que el código funcione, no olvides importar json desde la biblioteca estándar de Python:

import json 

Paso n.º 11: Finalizar la lógica de scraping

Ahora, el script de scraping de LinkedIn está básicamente completo. Aún así, hay algunas mejoras que puedes hacer:

  1. Limitar el número de trabajos rastreados
  2. Añade algunos registros para supervisar el progreso del script

El primer punto es importante porque:

  1. No quieres sobrecargar el servidor de destino con demasiadas solicitudes de tu raspador de LinkedIn
  2. No sabes cuántos trabajos hay en una sola página

Por lo tanto, tiene sentido limitar el número de trabajos rastreados de la siguiente manera:

scraping_limit = 10
jobs_to_scrape = job_urls[:scraping_limit]

jobs = []
for job_url in jobs_to_scrape:
    # ...

Esto limitará las páginas rastreadas a un máximo de 10.

A continuación, añade algunas sentencias print() para supervisar lo que hace el script mientras se ejecuta:

public_job_search_url = "https://www.linkedin.com/jobs/search?keywords=Software%2BEngineer&location=New%20York%2C%20New%20York%2C%20United%20States&geoId=102571732&trk=public_jobs_jobs-search-bar_search-submit&position=1&pageNum=0"

print("Iniciando la recuperación de empleos desde la URL de búsqueda de LinkedIn...")

job_urls = retrieve_job_urls(public_job_search_url)

print(f"URL de {len(job_urls)} empleos recuperadasn")

scraping_limit = 10
jobs_to_scrape = job_urls[:scraping_limit]

print(f"Rastreando {len(jobs_to_scrape)} empleos...n")

jobs = []
for job_url in jobs_to_scrape:
    print(f"Starting data extraction on "{job_url}"")

    job = scrape_job(job_url)
    jobs.append(job)

    print(f"Job scraped")

print(f"nExporting {len(jobs)} scraped jobs to JSON")
file_name = "jobs.json"
with open(file_name, "w", encoding="utf-8") as file:
    json.dump(jobs, file, indent=4, ensure_ascii=False)

print(f"Jobs successfully saved to "{file_name}"n")

La lógica de registro te ayudará a realizar un seguimiento del progreso del raspador, lo cual es esencial teniendo en cuenta que pasa por varios pasos.

Paso n.º 12: Ponlo todo junto

Este es el código final de tu script de scraping de LinkedIn:

from bs4 import BeautifulSoup
import requests
import json

def retrieve_job_urls(job_search_url):
    # Realiza una solicitud HTTP GET para obtener el HTML de la página.
    response = requests.get(job_search_url)

    # Accede al HTML y analízalo.
    html = response.text
    soup = BeautifulSoup(html, "html.parser")

    # Dónde almacenar los datos extraídos
    job_urls = []

    # Lógica de extracción
    job_url_elements = soup.select("[data-tracking-control-name="public_jobs_jserp-result_search-card"]")
    for job_url_element in job_url_elements:
      # Extraer la URL de la página de empleo y añadirla a la lista
      job_url = job_url_element["href"]
      job_urls.append(job_url)

    return job_urls

def scrape_job(job_url):
    # Enviar una solicitud HTTP GET para obtener el HTML de la página
    response = requests.get(job_url)

    # Acceder al texto HTML de la respuesta y analizarlo.
    html = response.text
    soup = BeautifulSoup(html, "html.parser")

    # Lógica de scraping.
    title_element = soup.select_one("h1")
    title = title_element.get_text().strip()

    company_element = soup.select_one("[data-tracking-control-name="public_jobs_topcard-org-name"]")
    company_name = company_element.get_text().strip()
    company_url = company_element["href"]

    location_element = soup.select_one(".topcard__flavor--bullet")
    location = location_element.get_text().strip()

    applicants_element = soup.select_one(".num-applicants__caption")
    applicants = applicants_element.get_text().strip()

    salary_element = soup.select_one(".salary")
    if salary_element is not None:
      salary = salary_element.get_text().strip()
    else:
       salary = None

    description_element = soup.select_one(".description__text .show-more-less-html")
    description = description_element.get_text().strip()

    criteria = []
    criteria_elements = soup.select(".description__job-criteria-list li")
    for criteria_element in criteria_elements:
        name_element = criteria_element.select_one(".description__job-criteria-subheader")
        name = name_element.get_text().strip()

        value_element = criteria_element.select_one(".description__job-criteria-text")
        value = value_element.get_text().strip()

        criteria.append({
            "name": name,
            "value": value
        })

    # Recopilar los datos extraídos y devolverlos
    job = {
        "url": job_url,
        "title": title,
        "company": {
            "name": company_name,
            "url": company_url
        },
        "location": location,
        "applications": applicants,
        "salary": salary,
        "description": description,
        "criteria": criteria
    }
    return job

# La URL pública de la página de búsqueda de empleos de LinkedIn
public_job_search_url = "https://www.linkedin.com/jobs/search?keywords=Software%2BEngineer&location=New%20York%2C%20New%20York%2C%20United%20States&geoId=102571732&trk=public_jobs_jobs-search-bar_search-submit&position=1&pageNum=0"

print("Iniciando la recuperación de empleos desde la URL de búsqueda de LinkedIn...")

# Recuperando las URL individuales de cada empleo en la página
job_urls = retrieve_job_urls(public_job_search_url)

print(f"URL de {len(job_urls)} empleos recuperadasn")

# Recopilar solo hasta 10 empleos de la página
scraping_limit = 10
jobs_to_scrape = job_urls[:scraping_limit]

print(f"Recopilando {len(jobs_to_scrape)} empleos...n")

# Recopilar datos de cada página de puestos de trabajo
jobs = []
for job_url in jobs_to_scrape:
    print(f"Iniciando la extracción de datos en "{job_url}"")

    job = scrape_job(job_url)
    jobs.append(job)

    print(f"Puesto de trabajo recopilado")

# Exportar los datos extraídos a CSV
print(f"nExportando {len(jobs)} trabajos extraídos a JSON")
file_name = "jobs.json"
with open(file_name, "w", encoding="utf-8") as file:
    json.dump(jobs, file, indent=4, ensure_ascii=False)

print(f"Empleos guardados correctamente en "{file_name}"n")

Ejecuta el siguiente comando:

python scraper.py

El raspador de LinkedIn debería registrar la siguiente información:

Iniciando la recuperación de trabajos desde la URL de búsqueda de LinkedIn...
Se han recuperado 60 URL de trabajos                                                                                                        
Raspando 10 trabajos...

Iniciando la extracción de datos en «https://www.linkedin.com/jobs/view/software-engineer-recent-graduate-at-paypal-4149786397?position=1&pageNum=0&refId=nz9sNo7HULREru1eS2L9nA%3D%3D&trackingId=uswFC6EjKkfCPcv0ykaojw%3D%3D»
Puesto extraído

# omitido por brevedad...

Inicio de la extracción de datos en «https://www.linkedin.com/jobs/view/software-engineer-full-stack-at-paces-4090771382?position=2&pageNum=0&refId=UKcPcvFZMOsZrn0WhZYqtg%3D%3D&trackingId=p6UUa6cgbpYS1gDkRlHV2g%3D%3D"
Trabajo extraído

Exportando 10 trabajos extraídos a JSON
Trabajos guardados correctamente en «jobs.json»

De las 60 páginas de empleo que encontró, el script solo extrajo 10 empleos. Por lo tanto, el archivo de salida jobs.json generado por el script contendrá exactamente 10 puestos de trabajo:

[
    {
        "url": "https://www.linkedin.com/jobs/view/software-engineer-recent-graduate-at-paypal-4149786397?position=1&pageNum=0&refId=UKcPcvFZMOsZrn0WhZYqtg%3D%3D&trackingId=UzOyWl8Jipb1TFAGlLJxqw%3D%3D",
        «title»: «Ingeniero de software - Recién graduado»,
        «company»: {
            «name»: «PayPal»,
            «url»: «https://www.linkedin.com/company/paypal?trk=public_jobs_topcard-org-name»
        },
        "location": "Nueva York, NY",
        "applications": "Más de 200 candidatos",
        "salary": null,
        "description": "Omitido por brevedad...",
        «criterios»: [
            {
                «nombre»: «Nivel de antigüedad»,
                «valor»: «No aplicable»
            },
            {
                «nombre»: «Tipo de empleo»,
                «valor»: «A tiempo completo»
            },
            {
                "nombre": "Función del puesto",
                "valor": "Ingeniería"
            },
            {
                "nombre": "Sectores",
                "valor": "Desarrollo de software, servicios financieros y tecnología, información e Internet"
            }
        ]
    },

    // otros 8 puestos...

    {
        "url": "https://www.linkedin.com/jobs/view/software-engineer-full-stack-at-paces-4090771382?position=2&pageNum=0&refId=UKcPcvFZMOsZrn0WhZYqtg%3D%3D&trackingId=p6UUa6cgbpYS1gDkRlHV2g%3D%3D",
        "title": "Ingeniero de software (Full-Stack)",
        "company": {
            "name": "Paces",
            "url": "https://www.linkedin.com/company/pacesai?trk=public_jobs_topcard-org-name"
        },
        "location": "Brooklyn, NY",
        "applications": "Más de 200 candidatos",
        "salary": "$150,000.00/año - $200,000.00/año",
        "description": "Omitido por brevedad...",
        "criteria": [
            {
                "name": "Nivel de antigüedad",
                "value": "Nivel inicial"
            },
            {
                "name": "Tipo de empleo",
                "value": "Tiempo completo"
            },
            {
                "name": "Función del puesto",
                "value": "Ingeniería y tecnología de la información"
            },
            {
                "name": "Sectores",
                "value": "Desarrollo de software"
            }
        ]
    },
]

¡Et voilà! El scraping web de LinkedIn en Python no es tan difícil.

Optimizar el scraping de datos de LinkedIn

El script que hemos creado puede hacer que el scraping de LinkedIn parezca una tarea sencilla, pero no es así. El muro de inicio de sesión y las técnicas de ofuscación de datos pueden convertirse rápidamente en un reto, especialmente a medida que se amplía la operación de scraping.

Además, LinkedIn cuenta con mecanismos de limitación de velocidad para bloquear los scripts automatizados que realizan demasiadas solicitudes. Una solución habitual es rotar la dirección IP en Python, pero eso requiere un esfuerzo adicional.

Además, hay que tener en cuenta que LinkedIn está en constante evolución, por lo que los esfuerzos y los costes de mantenimiento de su raspador no son insignificantes. LinkedIn alberga un tesoro de datos en diversos formatos, desde ofertas de empleo hasta artículos. Para recuperar toda esta información, sería necesario crear diferentes raspadores y gestionarlos todos.

Olvídate de las complicaciones con la API LinkedIn Raspador de Bright Data. Esta herramienta dedicada puede extraer todos los datos de LinkedIn que necesites y entregarlos a través de integraciones sin código o mediante simples puntos finales que puedes llamar con cualquier cliente HTTP.

Úsela para extraer perfiles, publicaciones, empresas, ofertas de empleo y mucho más de LinkedIn en cuestión de segundos, sin tener que gestionar toda una arquitectura de extracción.

Conclusión

En este tutorial paso a paso, ha aprendido qué es un raspador de LinkedIn y los tipos de datos que puede recuperar. También ha creado un script de Python para extraer ofertas de empleo de LinkedIn.

El reto es que LinkedIn utiliza bloqueos de IP y muros de inicio de sesión para bloquear los scripts automatizados. Evita estos problemas con nuestro raspador de LinkedIn.

Si el Scraping web no es lo tuyo, pero sigues interesado en los datos, ¡echa un vistazo a nuestros Conjuntos de datos de LinkedIn listos para usar!

Crea hoy mismo una cuenta gratuita en Bright Data para probar nuestras API de raspadores o explorar nuestros Conjuntos de datos.