DEV Community

FairPrice
FairPrice

Posted on

How to Scrape LinkedIn Job Listings in 2026 (No Login Required)

LinkedIn is the largest professional network in the world, and its job listings are a goldmine of data — salaries, hiring trends, company growth signals. The problem? LinkedIn locks most of its data behind authentication and aggressively blocks scrapers.

But there is a loophole. LinkedIn's guest job search endpoint (linkedin.com/jobs-guest/) serves public job listings without requiring login. The LinkedIn Jobs Scraper on Apify leverages this to extract job data at scale — no cookies, no login, no risk to your LinkedIn account.

Why LinkedIn Jobs Data Is Public

LinkedIn intentionally makes job listings publicly accessible. It is in their interest — they want job seekers to find listings through Google. The /jobs-guest/ endpoint serves the same data you see when you Google "software engineer jobs LinkedIn" without being logged in.

This means:

  • No authentication needed — the data is served to anonymous visitors
  • No account risk — you are not logged in, so there is nothing to ban
  • Legal gray area favors you — public data accessible without circumventing any access controls

What You Can Extract

The scraper pulls structured data from each job listing:

  • Job title and description (full text)
  • Company name and company URL
  • Location (city, state, country, remote/hybrid/onsite)
  • Salary range (when posted — increasingly common in 2026 due to pay transparency laws)
  • Posted date and application deadline
  • Seniority level (entry, mid, senior, director, executive)
  • Employment type (full-time, part-time, contract, internship)
  • Industry and job function
  • Number of applicants

Quick Start on Apify

  1. Open LinkedIn Jobs Scraper
  2. Enter your search parameters:
    • Keywords: e.g., "machine learning engineer"
    • Location: e.g., "San Francisco, CA"
    • Company: e.g., "Google" (optional)
  3. Set max results (default: 100)
  4. Click Run

Results export to JSON, CSV, or Excel.

Python Code Example: Scraping Jobs Programmatically

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_API_TOKEN")

run_input = {
    "keywords": "data engineer",
    "location": "United States",
    "maxResults": 200,
    "dateSincePosted": "past-week"
}

run = client.actor("cryptosignals/linkedin-jobs-scraper").call(run_input=run_input)

for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    salary = job.get("salary", "Not listed")
    print(f"{job['title']} at {job['company']}{job['location']}")
    print(f"  Salary: {salary}")
    print(f"  Posted: {job['postedDate']}")
    print()
Enter fullscreen mode Exit fullscreen mode

Install the client:

pip install apify-client
Enter fullscreen mode Exit fullscreen mode

Filtering and Targeting

The scraper supports the same filters LinkedIn's search does:

By Company

Track hiring at specific companies:

run_input = {
    "keywords": "engineer",
    "company": "Stripe",
    "maxResults": 50
}
Enter fullscreen mode Exit fullscreen mode

By Location

Compare job markets across cities:

cities = ["San Francisco", "New York", "Austin", "London", "Berlin"]
for city in cities:
    run_input = {
        "keywords": "software engineer",
        "location": city,
        "maxResults": 100
    }
    run = client.actor("cryptosignals/linkedin-jobs-scraper").call(run_input=run_input)
    items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
    print(f"{city}: {len(items)} jobs found")
Enter fullscreen mode Exit fullscreen mode

By Date

Get only fresh listings:

run_input = {
    "keywords": "AI researcher",
    "dateSincePosted": "past-24-hours",
    "maxResults": 50
}
Enter fullscreen mode Exit fullscreen mode

Real-World Use Cases

Job Market Analytics

Track hiring trends over time. Run the scraper weekly for specific keywords and build a time series of job postings. Are "AI engineer" roles growing faster than "data scientist" roles? How quickly did remote jobs decline (or not) in 2026? The data tells the story.

Salary Benchmarking

With pay transparency laws expanding across the US and EU, more LinkedIn job posts include salary ranges. Scrape thousands of listings to build salary benchmarks by role, location, company size, and seniority. This data sells — recruiters, HR teams, and job boards all need it.

Company Hiring Tracker

Monitor when companies ramp up or slow down hiring. A sudden burst of engineering roles at a startup could signal a funding round. A hiring freeze at a public company could signal trouble. Track 50+ companies and you have an intelligence feed.

Competitive Intelligence for Recruiters

Recruiters can use this to see exactly what their competitors are offering — salary ranges, benefits mentioned in descriptions, required skills, and seniority levels. Build a dashboard that updates weekly.

Dealing with Anti-Bot Protection

LinkedIn's guest endpoints are public, but they do have basic protections:

  • Rate limiting — too many requests from one IP get throttled
  • CAPTCHA challenges — triggered by suspicious patterns
  • IP blocking — temporary blocks on aggressive scrapers

The Apify actor handles most of this with built-in request throttling and retry logic. For high-volume jobs (1000+ listings per run), you may want to add a proxy layer.

ScraperAPI is a solid option for this — it rotates proxies automatically, handles CAPTCHAs, and has a free tier for testing. You can configure it as a proxy in your Apify actor settings or use it in your own scripts:

import requests

params = {
    "api_key": "YOUR_SCRAPERAPI_KEY",
    "url": "https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?keywords=python&location=US&start=0"
}

response = requests.get("http://api.scraperapi.com", params=params)
print(response.text)
Enter fullscreen mode Exit fullscreen mode

Building a Salary Database

Here is a complete example that scrapes jobs across multiple roles and stores the results in a CSV:

import csv
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_API_TOKEN")

roles = [
    "software engineer",
    "data engineer",
    "product manager",
    "machine learning engineer",
    "devops engineer"
]

all_jobs = []
for role in roles:
    run = client.actor("cryptosignals/linkedin-jobs-scraper").call(run_input={
        "keywords": role,
        "location": "United States",
        "maxResults": 100
    })
    for job in client.dataset(run["defaultDatasetId"]).iterate_items():
        if job.get("salary"):
            all_jobs.append({
                "role": role,
                "title": job["title"],
                "company": job["company"],
                "location": job["location"],
                "salary": job["salary"]
            })

with open("salary_data.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["role", "title", "company", "location", "salary"])
    writer.writeheader()
    writer.writerows(all_jobs)

print(f"Saved {len(all_jobs)} jobs with salary data")
Enter fullscreen mode Exit fullscreen mode

Output Format

Clean, structured JSON per job:

{
  "title": "Senior Data Engineer",
  "company": "Stripe",
  "location": "San Francisco, CA (Hybrid)",
  "salary": "$180,000 - $250,000/yr",
  "postedDate": "2026-03-01",
  "seniorityLevel": "Mid-Senior level",
  "employmentType": "Full-time",
  "applicants": 47,
  "description": "We are looking for a Senior Data Engineer to...",
  "url": "https://www.linkedin.com/jobs/view/3456789"
}
Enter fullscreen mode Exit fullscreen mode

Pricing

The scraper runs on Apify's pay-per-use platform. Scraping 200 job listings typically costs $0.10-0.30 in compute credits. No subscription needed.

Summary

LinkedIn job listings are publicly accessible data, and with the right tools you can extract them at scale without risking your account or dealing with authentication headaches. The LinkedIn Jobs Scraper handles the scraping infrastructure — you focus on what to do with the data.

Whether you are building a salary benchmarking tool, tracking hiring trends, or feeding a job aggregator, this gives you structured LinkedIn data in minutes, not days.

Top comments (0)