Skip to Content

Membuat LinkedIn Jobs Scraper + Ekstraksi Skills

Panduan Lengkap

LinkedIn merupakan sumber berharga untuk data pekerjaan, namun tidak menyediakan API publik untuk mengakses informasi ini secara terstruktur. Pada tutorial ini, saya akan menjelaskan cara membuat scraper untuk mengumpulkan informasi lowongan pekerjaan dari LinkedIn dan mengekstrak skills yang dibutuhkan menggunakan teknik NLP.


Struktur Metodologi LinkedIn Jobs Scraper dengan Ekstraksi Skills

1. Persiapan dan Setup

  • Import library utama (pandas, numpy, matplotlib, seaborn)
  • Import library pendukung (requests, BeautifulSoup, re, datetime)
  • Konfigurasi warnings dan headers untuk web scraping

2. Persiapan Data Referensi

  • Definisi daftar lokasi (negara bagian dan kota)
  • Setup kata kunci pencarian pekerjaan
  • Konfigurasi parameter filter:
    • Filter waktu posting (24 jam, seminggu, sebulan)
    • Filter jenis pekerjaan (onsite, remote, hybrid)
    • Filter level pengalaman (magang, entry level, senior)

3. Implementasi Model NLP untuk Ekstraksi Skills

  • Instalasi library transformers dan flair
  • Loading model Named Entity Recognition (NER)
  • Konfigurasi fungsi ekstraksi skills dari teks deskripsi pekerjaan

4. Implementasi Fungsi Scraping LinkedIn

  • Definisi fungsi utama scrape_jobs
  • Implementasi loop untuk berbagai kombinasi filter
  • Pengambilan data pekerjaan melalui pagination
  • Ekstraksi data penting:
    • Judul pekerjaan
    • Nama perusahaan
    • Lokasi
    • Deskripsi pekerjaan
    • Link pekerjaan
  • Ekstraksi skills menggunakan model NER
  • Penanganan error dan timeout

5. Pengumpulan dan Pemrosesan Data

  • Eksekusi scraping untuk berbagai kombinasi lokasi dan posisi
  • Penggabungan hasil menjadi satu DataFrame
  • Penghapusan data duplikat
  • Reset index

6. Penyimpanan Data dan Analisis

  • Export data ke file CSV dengan timestamp
  • Potensi analisis lanjutan:
    • Visualisasi tren skills yang dicari
    • Analisis distribusi jenis pekerjaan
    • Perbandingan kebutuhan skills berdasarkan posisi

7. Tantangan dan Penanganan

  • Penanganan koneksi terputus
  • Batasan rate limiting dari LinkedIn
  • Perubahan struktur HTML LinkedIn

-----------------------------------------------------

1. Persiapan dan Import Library

Pertama, kita perlu mengimport library-library penting untuk web scraping, manipulasi data, dan NLP:

python

# Library utama import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # Library pendukung import os import warnings warnings.filterwarnings("ignore") import requests from bs4 import BeautifulSoup import time import re import traceback from datetime import datetime

Penjelasan:

  • requests: Digunakan untuk mengirim HTTP requests ke server LinkedIn
  • BeautifulSoup: Library parsing HTML yang akan membantu kita mengekstrak informasi dari halaman web
  • pandas: Untuk manipulasi dan analisis data dalam format tabel
  • re: Library regex untuk pattern matching pada teks
  • datetime: Untuk mencatat tanggal scraping yang akan berguna untuk tracking data

2. Persiapan Data Referensi

Untuk membuat scraper yang komprehensif, kita perlu mendefinisikan beberapa data referensi seperti lokasi, kata kunci pencarian, dan filter:

python

# Daftar negara bagian di Jerman (contoh dataset) states = [ "Baden-Württemberg", "Bavaria", "Berlin", "Brandenburg", "Bremen", "Hamburg", "Hesse", "Lower Saxony", "Mecklenburg-Vorpommern", "North Rhine-Westphalia", "Rhineland-Palatinate", "Saarland", "Saxony", "Saxony-Anhalt", "Schleswig-Holstein", "Thuringia" ] # Daftar kota-kota besar di Jerman cities = [ "Berlin", "Hamburg", "Munich", "Cologne", "Frankfurt", # ... kota-kota lainnya ] # Kata kunci pencarian untuk pekerjaan IT it_job=[ "Data%20Engineer", "Data%20Scientist", "machine%20learning" ] # Parameter filter untuk waktu posting Past_month="f_TPR=r2592000" Past_week="f_TPR=r604800" Past_24_hours="f_TPR=r86400" # Parameter filter untuk jenis pekerjaan onsite="f_WT=1" remote="f_WT=2" hybrid="f_WT=3" # Parameter filter untuk level pengalaman internship="f_E=1" entry_level="f_E=2" associate="f_E=3" mid_senior="f_E=4" director="f_E=5" Executive="f_E=6"

Penjelasan:

  • Data lokasi memungkinkan kita untuk mencari pekerjaan berdasarkan wilayah geografis
  • Kata kunci pencarian diformat dengan %20 (URL encoding untuk spasi) agar bisa digunakan dalam URL
  • Parameter filter waktu memungkinkan kita untuk membatasi hasil ke posting terbaru
  • Parameter jenis pekerjaan memungkinkan kita memfilter berdasarkan mode kerja (onsite, remote, hybrid)
  • Parameter level pengalaman memungkinkan kita memfilter berdasarkan senioritas posisi

3. Persiapan Model NER untuk Ekstraksi Skills

Untuk mengekstrak skills dari deskripsi pekerjaan, kita akan menggunakan model Named Entity Recognition (NER) dari Flair yang dikhususkan untuk deteksi skills:

python

# Install library yang diperlukan !pip install transformers flair # Import model Flair untuk NER from flair.models import SequenceTagger from flair.data import Sentence # Load model NER yang telah dilatih khusus untuk mendeteksi skills flair_model = SequenceTagger.load("kaliani/flair-ner-skill") # Fungsi untuk ekstraksi skills dari teks def get_skills(input_text): # Membuat objek Sentence sentence = Sentence(input_text) # Menggunakan model Flair untuk prediksi entitas flair_model.predict(sentence) description = [] # Ekstraksi entitas bernama dari hasil prediksi for entity in sentence.get_spans("ner"): description.append(entity.text) return description

Penjelasan:

  • Model kaliani/flair-ner-skill adalah model khusus untuk mendeteksi skills dalam teks
  • Fungsi get_skills menerima teks deskripsi pekerjaan dan mengembalikan daftar skills yang terdeteksi
  • Proses NER mengidentifikasi dan mengklasifikasikan entitas bernama dalam teks (dalam hal ini, skills teknis, soft skills, dll.)
  • Model ini mampu mengenali berbagai jenis skills seperti bahasa pemrograman, frameworks, tools, dan soft skills

4. Fungsi Utama untuk Scraping

Sekarang kita akan membuat fungsi utama untuk melakukan scraping data pekerjaan dari LinkedIn:

python

def scrape_jobs(location0, position): # Mapping level pekerjaan level_mapping = { "internship": "f_E=1", "entry_level": "f_E=2", "mid_senior": "f_E=4" } # Mapping jenis pekerjaan work_type_mapping = { "onsite": "f_WT=1", "hybrid": "f_WT=3" } # Headers untuk request (penting untuk menghindari blocking) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } job_data = [] # Loop untuk setiap kombinasi jenis pekerjaan dan level for WorkType1, WorkType2 in work_type_mapping.items(): for levelMapping1, levelMapping2 in level_mapping.items(): # Membuat URL dasar dengan parameter pencarian url_basic = "https://www.linkedin.com/jobs/search/?location="+location0+"&keywords="+position+"&"+levelMapping2+"&"+WorkType2+"&f_TPR=r86400" k = -25 url = url_basic + "&start=" + str(0) # Mengirim GET request dengan headers request = requests.get(url, headers=headers) data = request.text soup = BeautifulSoup(data) try: # Ekstrak jumlah hasil pencarian dari judul halaman titletag = soup.find('title') if titletag is not None: input_string = str(titletag.get_text()).split(" ")[0] digits_only = re.sub(r'\D', '', input_string) nbre_offers = int(digits_only) else: nbre_offers = 230 # Hitung jumlah halaman yang perlu di-scrape nbre_pages = (int(nbre_offers/25))*25 # Loop untuk setiap halaman hasil while(k <= nbre_offers): k = k + 25 locations = [] titles = [] countries = [] links = [] job_description = [] company_name = [] skills = [] datelist = [] # Update URL untuk halaman berikutnya url = url_basic + "&start=" + str(k) request = requests.get(url) data = request.text soup = BeautifulSoup(data) # Ekstrak elemen-elemen yang dibutuhkan job_links = soup.findAll("a", {"class":"base-card__full-link"}) title = soup.findAll("h3", {"class":"base-search-card__title"}) location = soup.findAll("span", {"class":"job-search-card__location"}) country = soup.findAll("span", {"class":"job-search-card__location"}) names = soup.findAll("a", {"class":"hidden-nested-link"}) # Ekstrak judul pekerjaan for i in title: x = i.text.replace("\n", " ").strip(" ") titles.append(x) # Ekstrak lokasi for i in location: x = i.text.replace("\n", " ").strip(" ") locations.append(x) # Ekstrak negara for i in country: x = i.text.replace("\n", " ").strip(" ").split(',')[-1] countries.append(x) # Ekstrak link dan deskripsi pekerjaan for i in job_links: x = str(i["href"].split("?refId=")[0]) links.append(x) # Request untuk halaman detail pekerjaan request = requests.get(x, timeout=230, headers=headers) data = request.text soup = BeautifulSoup(data) # Ekstrak deskripsi pekerjaan job_description_div = soup.find('div', class_='description__text description__text--rich') if job_description_div is not None: job_description.append(job_description_div.get_text()) # Ekstrak skills dari deskripsi skills.append(get_skills(str(job_description_div.get_text()))) else: skills.append("No skills extracted") job_description.append("No job description available") # Ekstrak nama perusahaan for i in names: x = i.text.replace("\n", " ").strip(" ") company_name.append(x) # Susun data untuk setiap pekerjaan for j in range(len(job_links)): job_data.append({ "position": position.replace("%20", " "), "date": today_date_string, "WorkType": WorkType1, "levelMapping": levelMapping1, "Title": titles[j], "Company": company_name[j], "Location": locations[j], "Link": links[j], "job description": job_description[j], "skills": skills[j] }) # Keluar dari loop jika tidak ada hasil lagi if len(job_links) == 0: break except Exception as error: print(error) print(url) pass # Konversi ke DataFrame job_df = pd.DataFrame(job_data) return job_df

Penjelasan:

  • Fungsi ini menerima lokasi dan posisi pekerjaan sebagai parameter
  • Untuk setiap kombinasi jenis pekerjaan (onsite/hybrid) dan level pengalaman, scraper akan mencari pekerjaan yang sesuai
  • Scraper navigasi melalui semua halaman hasil, mengekstrak informasi penting seperti judul, perusahaan, lokasi
  • Untuk setiap pekerjaan, scraper mengunjungi halaman detail untuk mengekstrak deskripsi lengkap
  • Deskripsi pekerjaan kemudian diproses oleh model NER untuk mengekstrak skills
  • Header User-Agent penting untuk menghindari pemblokiran oleh LinkedIn
  • Data disimpan dalam struktur dictionary, yang kemudian dikonversi ke DataFrame pandas

5. Menjalankan Scraper untuk Berbagai Kombinasi

Sekarang kita akan menjalankan scraper untuk berbagai kombinasi lokasi dan posisi pekerjaan:

python

# Dapatkan tanggal hari ini untuk timestamp data today_date = datetime.today().date() today_date_string = today_date.strftime('%Y-%m-%d') # List untuk menyimpan hasil scraping result_df = [] # Loop untuk setiap kombinasi lokasi dan posisi for location in cities + states: for position in it_job: result_df.append(scrape_jobs(location, position)) # Gabungkan semua DataFrame hasil combined_df = pd.concat(result_df) # Hapus duplikat berdasarkan beberapa kolom combined_df = combined_df.drop_duplicates(subset=['position', 'Title', 'Company', 'Location']) # Reset index jika diperlukan combined_df = combined_df.reset_index(drop=True) # Simpan hasil ke file CSV combined_df.to_csv("linkedin_offers" + today_date_string + ".csv")

Penjelasan:

  • Kita menjalankan scraper untuk semua kombinasi lokasi (kota dan negara bagian) dan posisi pekerjaan
  • Hasil dari setiap kombinasi disimpan dalam list result_df
  • Semua DataFrame digabungkan menjadi satu menggunakan pd.concat()
  • Duplikat dihapus berdasarkan kombinasi posisi, judul, perusahaan, dan lokasi
  • Hasil akhir disimpan ke file CSV dengan timestamp tanggal saat ini

6. Analisis Hasil dan Visualisasi

Setelah data terkumpul, kita dapat melakukan analisis dan visualisasi untuk mendapatkan insights:

python

# Tampilkan informasi dasar tentang dataset combined_df.info() combined_df.shape # Lihat beberapa sampel data combined_df.head() # Analisis distribusi skills def analyze_skills(df): # Flattenkan list skills menjadi satu list all_skills = [] for skill_list in df['skills']: if isinstance(skill_list, list): all_skills.extend(skill_list) # Hitung frekuensi setiap skill skill_counts = pd.Series(all_skills).value_counts().reset_index() skill_counts.columns = ['Skill', 'Count'] # Plot top skills plt.figure(figsize=(12, 8)) sns.barplot(x='Count', y='Skill', data=skill_counts.head(20)) plt.title('Top 20 Skills Demanded in Job Postings') plt.tight_layout() plt.show() return skill_counts # Visualisasi distribusi jenis pekerjaan def visualize_job_types(df): plt.figure(figsize=(10, 6)) sns.countplot(x='WorkType', data=df) plt.title('Distribution of Job Types') plt.show() plt.figure(figsize=(10, 6)) sns.countplot(x='levelMapping', data=df) plt.title('Distribution of Job Levels') plt.show() # Jalankan analisis skill_counts = analyze_skills(combined_df) visualize_job_types(combined_df)

Penjelasan:

  • Fungsi analyze_skills menghitung frekuensi kemunculan setiap skill di seluruh dataset
  • Visualisasi berupa bar chart untuk 20 skill teratas memberikan gambaran tentang skills yang paling dicari
  • Fungsi visualize_job_types menampilkan distribusi jenis pekerjaan (onsite/hybrid) dan level pengalaman

7. Tantangan dan Solusi dalam Scraping LinkedIn

Saat melakukan scraping dari LinkedIn, ada beberapa tantangan yang perlu diperhatikan:

  1. Rate Limiting: LinkedIn membatasi jumlah request yang dapat dilakukan dalam waktu tertentu. Solusinya:

python

# Tambahkan random delay antara requests import random def scrape_with_delay(url, headers): # Delay acak antara 2-5 detik time.sleep(random.uniform(2, 5)) return requests.get(url, headers=headers)

2. Deteksi Bot: LinkedIn dapat mendeteksi dan memblokir scraping otomatis. Solusinya:

python

# Rotasi User-Agent dan penggunaan proxy user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15', # Tambahkan lebih banyak user agent ] # Gunakan user agent acak untuk setiap request headers = { 'User-Agent': random.choice(user_agents) }

3. Perubahan Struktur HTML: LinkedIn dapat mengubah struktur HTML-nya kapan saja. Solusinya:

python

# Gunakan pendekatan yang lebih robust untuk ekstraksi data def extract_job_title(soup): # Coba beberapa selector yang berbeda selectors = [ "h3.base-search-card__title", ".job-card-container .job-card-list__title", # Selector alternatif lainnya ] for selector in selectors: try: elements = soup.select(selector) if elements: return [el.text.strip() for el in elements] except: continue return []

8. Peningkatan Kualitas Ekstraksi Skills

Model NER dasar untuk ekstraksi skills mungkin tidak sempurna. Kita bisa meningkatkan kualitasnya dengan:

python

# Implementasi metode hybrid untuk ekstraksi skills def enhanced_skill_extraction(job_description): # 1. Gunakan model NER ner_skills = get_skills(job_description) # 2. Gunakan pendekatan berbasis kamus skill_keywords = [ "Python", "Java", "SQL", "AWS", "Azure", "Docker", "Kubernetes", "Machine Learning", "Deep Learning", "NLP", "Data Analysis", # Tambahkan lebih banyak skills ] keyword_skills = [] for skill in skill_keywords: if re.search(r'\b' + re.escape(skill) + r'\b', job_description, re.IGNORECASE): keyword_skills.append(skill) # 3. Gabungkan hasil dan hilangkan duplikat all_skills = list(set(ner_skills + keyword_skills)) return all_skills

Penjelasan:

  • Pendekatan hybrid menggabungkan model NER dengan pencarian berbasis kamus
  • Reguler expression digunakan untuk menemukan kata kunci skill secara tepat
  • Hasil dari kedua pendekatan digabungkan dan duplikat dihilangkan

Kesimpulan

Scraper LinkedIn yang kita buat mampu mengumpulkan data lowongan pekerjaan secara komprehensif dan mengekstrak skills yang dibutuhkan menggunakan teknik NLP. Kerangka kerja ini dapat disesuaikan untuk berbagai kebutuhan analisis pasar kerja, penelitian tren pekerjaan, atau persiapan karir.

Beberapa kemungkinan pengembangan lebih lanjut:

  1. Menambahkan analisis sentimen untuk memahami "tone" deskripsi pekerjaan
  2. Mengimplementasikan klasifikasi otomatis untuk mengkategorikan pekerjaan berdasarkan domain
  3. Mengembangkan dashboard interaktif untuk visualisasi tren pekerjaan
  4. Menambahkan analisis gaji untuk mempelajari korelasi antara skills dan kompensasi
  5. Mengintegrasikan dengan API portfolio untuk pengembangan karir yang ditargetkan

Dengan menggunakan tools dan teknik yang dijelaskan di atas, Anda dapat membangun sistem yang kuat untuk menganalisis tren pasar kerja dan membantu pengambilan keputusan karir.


3+ Tahun Nasihat Pencarian Kerja Data Science dalam 10 Menit (Bagian I)