Google Jobs API: How to Collect Job Listings from Search Results

Learn how to collect Google Jobs listings from search results with a SERP API. Use Python to extract job titles, companies, locations, descriptions, dates, salary signals, apply links, and export the data to CSV.

talor ai
最后更新于
11 分钟阅读

Google Jobs search results are useful when you want to understand hiring demand, track job-market trends, monitor competitors, or build a recruiting research workflow.

For example, you may want to collect:

  • Python developer jobs in New York

  • remote data analyst jobs

  • nursing jobs in Texas

  • marketing manager jobs in London

  • AI engineer jobs posted this week

  • competitor hiring activity by role or location

A SERP API gives you a cleaner workflow than manual browser scraping. You send a job search query, location, language, and result type. The API returns structured search data that your application can normalize, analyze, store, or pass into an AI workflow. Talordata SERP API provides structured search-result data from Google and major search engines, with JSON / HTML response formats and geo-targeted SERP data.

What We Will Build

We will create a Python script that:

Job search query
→ SERP API request
→ Google Jobs results
→ Extract job listing fields
→ Normalize data
→ Export listings to CSV

The final CSV can include:

  • job title

  • company name

  • location

  • source platform

  • posting date

  • job type

  • salary information

  • description

  • apply links

  • job ID

  • collected timestamp

This workflow is useful for recruiting analytics, labor-market research, competitor hiring monitoring, job aggregation, and AI-assisted market reports.

Why Use a SERP API for Job Listings?

You can try to collect job results manually, but job search pages are often dynamic and location-sensitive.

Common problems include:

  • dynamic rendering

  • changing layouts

  • inconsistent job-card fields

  • duplicate listings across platforms

  • missing salary data

  • different job sources for the same role

  • location-specific result changes

  • pagination and result expansion

  • blocked requests or CAPTCHA challenges

A SERP API lets you focus on the data workflow instead of the collection layer.

The basic flow becomes:

Send query + location
→ Receive structured job results
→ Normalize fields
→ Save to CSV, database, or dashboard

Step 1: Prepare Your API Key

Create a Talordata account and get your SERP API key from the dashboard. Talordata’s product page says new users can start with 1,000 free API responses, and its SERP API supports developer-friendly integration in Python, JavaScript, cURL, and Go.

Set your API key and endpoint as environment variables:

export TALORDATA_API_KEY="your_api_key_here"
export TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"

On Windows PowerShell:

$env:TALORDATA_API_KEY="your_api_key_here"
$env:TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"

Install the Python package:

pip install requests

Use the endpoint and parameter names shown in your Talordata dashboard or API docs. The code below keeps the request layer separate so you can adjust the exact endpoint, engine name, or authentication method in one place.

Step 2: Send a Google Jobs Request

A job search request usually needs a query, location, language, country, and result type.

import os
import requests


def require_env(name):
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value


def search_google_jobs(query, location="United States", language="en", country="us"):
    api_key = require_env("TALORDATA_API_KEY")
    endpoint = require_env("TALORDATA_SERP_ENDPOINT")

    payload = {
        "engine": "google_jobs",
        "q": query,
        "location": location,
        "hl": language,
        "gl": country,
        "output": "json"
    }

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    response = requests.post(
        endpoint,
        json=payload,
        headers=headers,
        timeout=30
    )

    response.raise_for_status()
    return response.json()

Some APIs may use query instead of q, or type=jobs instead of engine=google_jobs. Keep this function isolated so the rest of the script does not depend on one exact provider format.

Step 3: Extract Job Listings

Different APIs may return job results under different keys:

jobs_results
job_results
jobs
organic_results

A flexible parser makes your script easier to adapt.

from datetime import datetime, timezone


def clean_text(value):
    if not value:
        return ""
    return " ".join(str(value).split())


def join_list(value):
    if not value:
        return ""

    if isinstance(value, list):
        return " | ".join(clean_text(item) for item in value if item)

    return clean_text(value)


def get_job_results(serp_json):
    return (
        serp_json.get("jobs_results")
        or serp_json.get("job_results")
        or serp_json.get("jobs")
        or serp_json.get("organic_results")
        or []
    )


def extract_apply_links(item):
    apply_options = (
        item.get("apply_options")
        or item.get("apply_links")
        or item.get("related_links")
        or []
    )

    links = []

    for option in apply_options:
        if isinstance(option, dict):
            title = clean_text(option.get("title") or option.get("source"))
            link = option.get("link") or option.get("url")
            if link:
                links.append(f"{title}: {link}" if title else link)

    return " | ".join(links)


def normalize_job_results(serp_json, query, location):
    results = get_job_results(serp_json)
    collected_at = datetime.now(timezone.utc).isoformat()

    rows = []

    for index, item in enumerate(results, start=1):
        rows.append({
            "query": query,
            "location": location,
            "position": item.get("position") or item.get("rank") or index,
            "job_title": clean_text(item.get("title")),
            "company_name": clean_text(item.get("company_name") or item.get("company")),
            "job_location": clean_text(item.get("location")),
            "source": clean_text(item.get("via") or item.get("source")),
            "posted_at": clean_text(item.get("detected_extensions", {}).get("posted_at") or item.get("posted_at") or item.get("date")),
            "job_type": clean_text(item.get("detected_extensions", {}).get("schedule_type") or item.get("job_type") or item.get("schedule_type")),
            "salary": clean_text(item.get("detected_extensions", {}).get("salary") or item.get("salary")),
            "description": clean_text(item.get("description")),
            "extensions": join_list(item.get("extensions")),
            "job_id": item.get("job_id") or item.get("job_highlight_token") or item.get("id") or "",
            "job_link": item.get("link") or item.get("url") or "",
            "apply_links": extract_apply_links(item),
            "collected_at": collected_at
        })

    return rows

This normalized structure is easier to use in spreadsheets, dashboards, databases, and AI workflows.

Step 4: Export Job Listings to CSV

Now write the normalized job rows to a CSV file.

import csv


CSV_COLUMNS = [
    "query",
    "location",
    "position",
    "job_title",
    "company_name",
    "job_location",
    "source",
    "posted_at",
    "job_type",
    "salary",
    "description",
    "extensions",
    "job_id",
    "job_link",
    "apply_links",
    "collected_at"
]


def export_to_csv(rows, filename="google_jobs_results.csv"):
    if not rows:
        print("No job listings found.")
        return

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=CSV_COLUMNS)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Exported {len(rows)} job listings to {filename}")

Complete Python Example

import os
import csv
import requests

from datetime import datetime, timezone


CSV_COLUMNS = [
    "query",
    "location",
    "position",
    "job_title",
    "company_name",
    "job_location",
    "source",
    "posted_at",
    "job_type",
    "salary",
    "description",
    "extensions",
    "job_id",
    "job_link",
    "apply_links",
    "collected_at"
]


def require_env(name):
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value


def clean_text(value):
    if not value:
        return ""
    return " ".join(str(value).split())


def join_list(value):
    if not value:
        return ""

    if isinstance(value, list):
        return " | ".join(clean_text(item) for item in value if item)

    return clean_text(value)


def search_google_jobs(query, location="United States", language="en", country="us"):
    api_key = require_env("TALORDATA_API_KEY")
    endpoint = require_env("TALORDATA_SERP_ENDPOINT")

    payload = {
        "engine": "google_jobs",
        "q": query,
        "location": location,
        "hl": language,
        "gl": country,
        "output": "json"
    }

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    response = requests.post(
        endpoint,
        json=payload,
        headers=headers,
        timeout=30
    )

    response.raise_for_status()
    return response.json()


def get_job_results(serp_json):
    return (
        serp_json.get("jobs_results")
        or serp_json.get("job_results")
        or serp_json.get("jobs")
        or serp_json.get("organic_results")
        or []
    )


def extract_apply_links(item):
    apply_options = (
        item.get("apply_options")
        or item.get("apply_links")
        or item.get("related_links")
        or []
    )

    links = []

    for option in apply_options:
        if isinstance(option, dict):
            title = clean_text(option.get("title") or option.get("source"))
            link = option.get("link") or option.get("url")
            if link:
                links.append(f"{title}: {link}" if title else link)

    return " | ".join(links)


def normalize_job_results(serp_json, query, location):
    results = get_job_results(serp_json)
    collected_at = datetime.now(timezone.utc).isoformat()

    rows = []

    for index, item in enumerate(results, start=1):
        detected = item.get("detected_extensions") or {}

        rows.append({
            "query": query,
            "location": location,
            "position": item.get("position") or item.get("rank") or index,
            "job_title": clean_text(item.get("title")),
            "company_name": clean_text(item.get("company_name") or item.get("company")),
            "job_location": clean_text(item.get("location")),
            "source": clean_text(item.get("via") or item.get("source")),
            "posted_at": clean_text(detected.get("posted_at") or item.get("posted_at") or item.get("date")),
            "job_type": clean_text(detected.get("schedule_type") or item.get("job_type") or item.get("schedule_type")),
            "salary": clean_text(detected.get("salary") or item.get("salary")),
            "description": clean_text(item.get("description")),
            "extensions": join_list(item.get("extensions")),
            "job_id": item.get("job_id") or item.get("job_highlight_token") or item.get("id") or "",
            "job_link": item.get("link") or item.get("url") or "",
            "apply_links": extract_apply_links(item),
            "collected_at": collected_at
        })

    return rows


def export_to_csv(rows, filename="google_jobs_results.csv"):
    if not rows:
        print("No job listings found.")
        return

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=CSV_COLUMNS)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Exported {len(rows)} job listings to {filename}")


if __name__ == "__main__":
    query = "python developer jobs"
    location = "New York, United States"

    serp_json = search_google_jobs(
        query=query,
        location=location,
        language="en",
        country="us"
    )

    rows = normalize_job_results(serp_json, query, location)
    export_to_csv(rows)

After running the script, you should get:

google_jobs_results.csv

Example Output

Your CSV may look like this:

query,location,position,job_title,company_name,job_location,source,posted_at,job_type,salary,description,extensions,job_id,job_link,apply_links,collected_at
python developer jobs,"New York, United States",1,Python Developer,Example Company,"New York, NY",LinkedIn,2 days ago,Full-time,"$120K-$150K","Build backend services in Python...",Full-time | Remote,abc123,https://example.com/job,"LinkedIn: https://example.com/apply",2026-06-22T00:00:00Z

From here, you can send the data to Google Sheets, Airtable, a database, a recruiting dashboard, or an AI workflow.

Useful Parameters to Adjust

For Google Jobs collection workflows, these parameters usually matter:

Parameter

Why It Matters

q

Job search query, such as python developer jobs

location

City, region, or country for localized job results

gl

Country or market

hl

Language

engine / type

Search result type, such as jobs

start / pagination

Collect more results when supported

output

JSON is easier for automation

Location is especially important. Job results for the same title can change significantly by city, state, country, and remote-work wording.

Common Use Cases

Hiring market research

Track which roles are in demand across cities or industries.

Competitor hiring monitoring

Search for company names plus job titles to see what competitors are hiring for.

Salary signal analysis

Collect salary ranges when available and compare them by role, location, or company.

Job aggregation

Use Google Jobs results as a discovery layer, then send normalized rows into a database or matching system.

AI recruiting workflows

An AI agent can summarize hiring trends, group roles by function, identify repeated skills, or generate market snapshots from job search data.

Talordata’s SERP API product page lists AI search and agent integration as one of its use cases, with real-time SERP data used as input for RAG pipelines and AI agents.

Best Practices

Save raw responses during development. Job result fields can vary by query, country, and source platform.

Normalize company names carefully. The same employer may appear with slightly different names.

Keep job IDs when available. They help deduplicate listings across repeated runs.

Store timestamps. Job listings expire, move, or get reposted, so every row should include collected_at.

Separate discovery from verification. SERP data helps you find listings, but your workflow may need to fetch the original job page to confirm the full job description, requirements, and apply options.

Do not assume every listing has salary data. Many job cards omit salary, so your analysis should handle missing values.

FAQ

Can I collect Google Jobs results with Python?

Yes. You can use Python with a SERP API to send a job search query and receive structured job listings. The script above shows how to normalize common job fields and export them to CSV.

Is Google Jobs API the same as Google’s official APIs?

No. In this article, Google Jobs API means collecting Google Jobs-style search results through a SERP API. It is not the same as a first-party Google hiring or recruiting API.

What data can I collect from job search results?

Common fields include job title, company name, location, source, posted date, job type, salary information, description, job ID, job link, and apply links.

Can I use this for recruiting analytics?

Yes. You can use job listing data to analyze hiring demand, competitor hiring activity, salary signals, role distribution, and location trends.

Should I store job listings in CSV or a database?

CSV is fine for testing and small reports. For recurring collection, deduplication, trend tracking, and dashboards, a database is better.

立即开展您的数据业务

加入全球最强大的代理网络

免费试用