Google Jobs API:如何從搜尋結果收集職缺資料

了解如何使用 SERP API 從 Google Jobs 搜尋結果收集職缺資料,並用 Python 提取 job title、company、location、description、date、salary signals、apply links,最後匯出為 CSV。

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

Google Jobs 搜尋結果很適合用於了解 hiring demand、追蹤 job-market trends、監測 competitors,或建立 recruiting research workflow。

例如,你可能想收集:

  • New York 的 Python developer jobs

  • remote data analyst jobs

  • Texas 的 nursing jobs

  • London 的 marketing manager jobs

  • 本週發布的 AI engineer jobs

  • 按 role 或 location 監測 competitor hiring activity

SERP API 會比手動 browser scraping 更乾淨。你傳入 job search query、location、language 和 result type,API 返回 structured search data,後續可以 normalize、analyze、store,或傳給 AI workflow。Talordata SERP API 提供來自 Google 和主要搜尋引擎的 structured search-result data,支援 JSON / HTML response formats 和 geo-targeted SERP data。

我們要做什麼?

我們會建立一個 Python script:

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

最終 CSV 可以包含:

  • job title

  • company name

  • location

  • source platform

  • posting date

  • job type

  • salary information

  • description

  • apply links

  • job ID

  • collected timestamp

這個 workflow 適合 recruiting analytics、labor-market research、competitor hiring monitoring、job aggregation 和 AI-assisted market reports。

為什麼用 SERP API 收集 Job Listings?

你可以手動收集 job results,但 job search pages 通常是 dynamic 且 location-sensitive 的。

常見問題包括:

  • 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

使用 SERP API 後,你可以把精力放在 data workflow,而不是 collection layer。

基本流程變成:

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

Step 1:準備 API Key

建立 Talordata 帳號,並從 dashboard 取得 SERP API key。Talordata 產品頁說明,新使用者可以獲得 1,000 free API responses,並支援 Python、JavaScript、cURL、Go 等開發語言整合。

把 API key 和 endpoint 設為 environment variables:

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

Windows PowerShell:

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

安裝 Python package:

pip install requests

請使用 Talordata dashboard 或 API docs 中顯示的 endpoint 和 parameter names。下面的 code 將 request layer 獨立出來,方便你調整實際 endpoint、engine name 或 authentication method。

Step 2:發送 Google Jobs Request

Job search request 通常需要 query、location、language、country 和 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()

有些 API 可能使用 query 而不是 q,或使用 type=jobs 而不是 engine=google_jobs。把這個 function 獨立出來,可以避免其他 parsing 和 export code 被 provider format 綁死。

Step 3:提取 Job Listings

不同 API 可能會把 job results 放在不同 keys 下:

jobs_results
job_results
jobs
organic_results

使用 flexible parser 會更容易調整。

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

這樣整理後的格式,更適合放入 spreadsheets、dashboards、databases 和 AI workflows。

Step 4:匯出 Job Listings 到 CSV

接著把 normalized job rows 寫入 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}")

完整 Python 示例

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)

執行後會得到:

google_jobs_results.csv

輸出示例

CSV 可能像這樣:

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

接下來可以把資料送到 Google Sheets、Airtable、database、recruiting dashboard 或 AI workflow。

常用參數

Google Jobs收集工作流程通常會用到這些參數:

Parameter

為什麼重要

q

Job search query,例如 python developer jobs

location

City、region 或 country,用於 localized job results

gl

Country or market

hl

Language

engine / type

Search result type,例如 jobs

start / pagination

API 支援時,用於收集更多結果

output

JSON 更適合 automation

Location 很重要。同一個 job title 的結果,會因 city、state、country 和 remote-work wording 發生明顯差異。

常見使用場景

招聘市場調研

追蹤不同城市或產業中哪些 roles 需求更高。

競爭對手招聘監控

用 company names 加 job titles 搜尋,觀察 competitors 正在招聘哪些職位。

薪資訊號分析

在 salary ranges 可用時,按 role、location 或 company 比較薪資訊號。

工作聚合

把 Google Jobs results 當成 discovery layer,再將 normalized rows 寫入 database 或 matching system。

人工智慧招聘工作流程

AI agent 可以根據 job search data 總結 hiring trends、按 function 分組 roles、識別 repeated skills,或生成 market snapshots。

Talordata 的 SERP API 產品頁將 AI search 和 agent integration 列為使用場景之一,說明 real-time SERP data 可以作為 RAG pipelines 和 AI agents 的輸入。

最佳實踐

開發階段保存 raw responses。Job result fields 可能會因 query、country 和 source platform 而變化。

仔細 normalize company names。同一家公司可能會以略有不同的名稱出現。

盡可能保存 job IDs。它們有助於在重複收集時做 deduplication。

保存 timestamps。Job listings 會過期、移動或重新發布,所以每一行都應包含 collected_at

分離 discovery 和 verification。SERP data 幫助你找到 listings,但 workflow 可能還需要抓取 original job page,以確認完整 job description、requirements 和 apply options。

不要假設每條 listing 都有 salary data。很多 job cards 不會展示 salary,因此分析時要處理 missing values。

FAQ

可以用 Python 收集 Google Jobs results 嗎?

可以。你可以用 Python 搭配 SERP API 發送 job search query,並取得 structured job listings。上面的 script 示範了如何 normalize 常見 job fields,並匯出為 CSV。

Google Jobs API 是 Google 官方 API 嗎?

不是。這篇文章中的 Google Jobs API 指的是透過 SERP API 收集 Google Jobs-style search results,不是 Google 官方的一方 hiring 或 recruiting API。

可以從 job search results 收集哪些資料?

常見欄位包括 job title、company name、location、source、posted date、job type、salary information、description、job ID、job link 和 apply links。

可以用於 recruiting analytics 嗎?

可以。Job listing data 可以用來分析 hiring demand、competitor hiring activity、salary signals、role distribution 和 location trends。

應該把 job listings 保存為 CSV 還是 database?

小型測試和簡單報告可以使用 CSV。若要做 recurring collection、deduplication、trend tracking 和 dashboards,database 更合適。

立即开展您的数据业务

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

免费试用