Build a Job Search Tool with Python

Query a real jobs API and export filtered listings to Excel.

Introduction

30 Second Summary

Job searching is exhausting. You spend hours scrolling through LinkedIn, Indeed, and Glassdoor, copying links into spreadsheets, and repeating the whole process the next day.

In this project, you will build a Python script that automatically searches multiple job sites for data analyst roles, filters the results by your criteria, and exports everything into a clean Excel spreadsheet.

What You'll Build

A Python-based job search automation tool that connects to the JSearch API to pull real job listings from LinkedIn, Indeed, Glassdoor, and ZipRecruiter, then filters and exports the results to Excel.

By the end of this project, you'll have:

  • A working Python script that queries a real job search API for data analyst positions near San Antonio, TX.
  • A filtered Excel spreadsheet with job titles, companies, salaries, and direct application links ready for your job hunt.
  • A reusable tool you can re-run anytime to refresh your results or modify to search for different roles and locations.
  • Secret Mission: Add salary analysis that calculates average, min, and max salaries and highlights the top-paying roles.

Are there any prerequisites?

None. This project walks you through installing Python, setting up VS Code, and creating a free API account from scratch. No prior coding experience is required.

Install Python and VS Code

Before you can automate your job search, you need the right tools installed on your machine. Python is the programming language that powers your script, and VS Code is the code editor where you will write and run it.

In this step, you will install both tools from scratch, set up a dedicated project folder, and create an isolated environment for your project's packages.

In this step, get ready to:
  • Install Python 3.14 on your Windows machine.
  • Install VS Code with the Python extension.
  • Create a project folder with a virtual environment.
Download and install Python

Python is the language your job search script will be written in. You need version 3.14 installed on your machine before you can run any code.

  • Open your browser and go to the Python downloads page.
  • Click the large Download Python 3.14.6 button at the top of the page.
  • Once the file python-3.14.6-amd64.exe finishes downloading, double-click it to launch the installer.
  • On the first installer screen, check the box that says Add python.exe to PATH at the bottom.
  • Click Install Now and wait for the installation to complete.
  • Click Close when the installer shows "Setup was successful."

Why check Add python.exe to PATH?

PATH is a list of folders your computer searches when you type a command in the terminal. Checking this box tells Windows where to find Python, so you can type python in any terminal and it will work.

Now verify that Python installed correctly.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Check your Python version by running this command:
python --version

✔️ I see Python 3.14

You should see output like Python 3.14.6. Python is installed and ready to go.

ⓧ I see an older version

If you see a version number lower than 3.14 (for example, Python 3.9.7), an older Python installation is taking priority.

  • Close PowerShell.
  • Re-run the python-3.14.6-amd64.exe installer you just downloaded.
  • Select Modify, then make sure Add python.exe to PATH is checked.
  • Complete the installer, then open a new PowerShell window and run python --version again.

ⓧ Python is not recognized

If you see a message like "Python was not found" or "the term 'python' is not recognized," the PATH was not set up during installation.

  • Close PowerShell.
  • Re-run the python-3.14.6-amd64.exe installer.
  • Select Modify, click Next, and check the box Add Python to environment variables.
  • Click Install and wait for it to finish.
  • Open a brand new PowerShell window (the old one will not pick up PATH changes) and run python --version again.
Download and install VS Code

VS Code is a free code editor that gives you syntax highlighting, a built-in terminal, and extensions that make working with Python much smoother.

  • Open your browser and go to the VS Code download page.
  • Click the Download for Windows button to get the User Setup installer.
  • Run the downloaded .exe file and accept the default options.
  • Check Add to PATH if prompted, then click Install.
  • Click Finish when the installer completes.

Now open VS Code and install the Python extension.

  • Press the Windows key to open your search bar.
  • Type Visual Studio Code and press Enter to open it.
  • Press Ctrl+Shift+X to open the Extensions panel.
  • Type Python in the search box at the top.
  • Find the extension published by Microsoft (it should be the first result) and click Install.

What does the Python extension do?

The Python extension adds features like code autocompletion, error highlighting, and the ability to run Python files directly from VS Code. It also automatically detects virtual environments, which you will create next.

Don't see the extension?

Make sure you are typing Python in the Extensions search box (not the file search). The panel icon looks like four small squares in the left sidebar.

Help me find and install the Python extension in VS Code.

Create your project folder and virtual environment

A virtual environment is an isolated space where Python stores the packages for a specific project. This keeps your project's dependencies separate from anything else on your computer.

  • Switch back to your PowerShell window from earlier.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder by running this command:
mkdir job-search-tool
  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the job-search-tool folder, and click Select Folder.

VS Code reloads with your project folder open. You should see job-search-tool in the Explorer sidebar on the left.

  • Open the VS Code terminal by pressing Ctrl+` (the backtick key, above Tab).
  • Create a virtual environment by running this command:
python -m venv .venv

What does this command do?

python -m venv .venv tells Python to create a new virtual environment in a folder called .venv inside your project. The dot at the start makes it a hidden folder so it stays out of the way.

  • Activate the virtual environment by running:
.venv\Scripts\activate
  • Confirm the virtual environment is active by looking at your terminal prompt. You should see (.venv) at the beginning of the line.

Seeing a red error about execution policy?

PowerShell may block the activation script by default. If you see an error mentioning that running scripts is disabled on this system, run the following command first, then try activating again:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

After running that, try .venv\Scripts\activate again. You should now see (.venv) at the start of your prompt.

Help me fix the execution policy error when activating my virtual environment.

Your development environment is ready. Next up, you will install the Python packages your script needs and connect to the job search API.

Install Libraries and Set Up the API

Your Python environment is ready. Now you need the tools that let Python talk to the internet and work with data.

In this step, you will install three Python libraries, create a free account on a service that provides job listing data, and write the configuration that connects your script to that data source.

In this step, get ready to:
  • Install Python libraries for HTTP requests, data processing, and Excel export.
  • Create a free RapidAPI account and subscribe to the JSearch job search API.
  • Create the Python script with your API configuration.
Install the required packages

Your script needs three libraries to do its job. Each one handles a different piece of the puzzle.

  • In the VS Code terminal (where your virtual environment is still active), install the three packages by running this command:
pip install requests==2.34.2 pandas==3.0.3 openpyxl==3.1.5

What do these packages do?

  • requests lets Python send HTTP requests to websites and APIs.
  • pandas is a data analysis library that organizes information into tables called DataFrames.
  • openpyxl is the engine that pandas uses to write Excel files.
  • Wait for the installation to finish. You should see output ending with a line that says Successfully installed followed by the three package names and their versions.

Seeing a permission error or 'pip not found'?

  • Make sure your virtual environment is active. You should see (.venv) at the start of your terminal prompt. If not, run .venv\Scripts\activate again.
  • If you see a network timeout, check your internet connection and try the command again.

Help me fix a pip install error in my virtual environment.

Sign up for RapidAPI and subscribe to the JSearch API

Job listings live on sites like LinkedIn, Indeed, and Glassdoor. The JSearch API aggregates listings from all of these into one place, so your script can search them all with a single request.

RapidAPI is a marketplace that hosts thousands of APIs. You will create a free account there, then subscribe to the JSearch API's free plan.

  • Open your browser and go to rapidapi.com.
  • Click Sign Up and create a free account using your email or a social login.
  • Once signed in, navigate to the JSearch API page by searching for JSearch in the RapidAPI search bar.
  • Click the Pricing tab on the JSearch API page.
  • Select the BASIC plan (free, 200 requests per month, no credit card required) and click Subscribe.

Why JSearch?

JSearch pulls job data from Google for Jobs, which aggregates listings from LinkedIn, Indeed, Glassdoor, ZipRecruiter, and other major sites. Instead of scraping each site individually, one API call gets you results from all of them.

The free BASIC plan gives you 200 requests per month with a hard limit. This means you will never be charged. Once you hit 200 requests, the API simply stops responding until the next month.

  • After subscribing, click the Endpoints tab to return to the API playground.
  • Look for your API key in the Header Parameters section. The field labeled X-RapidAPI-Key contains your key.
  • Copy this key and keep it somewhere safe (a sticky note, a text file, or your clipboard). You will paste it into your script in the next substep.

Keep your API key private

Your API key is like a password. Do not share it publicly or commit it to a public repository. For this learning project, pasting it directly in the script is fine. In production, you would use environment variables instead.

Can't find JSearch on RapidAPI?

  • Try searching for JSearch (one word, capital J and S). The API is published by letscrape.
  • Make sure you are on rapidapi.com (not a different API marketplace).

Help me find and subscribe to the JSearch API on RapidAPI.

Create the configuration file

Now that you have your API key, you can write the script that will use it. The first section of your script defines the connection settings and search criteria.

  • In VS Code, create a new file by clicking File in the top menu bar, then New File.
  • Save the file immediately as job_search.py inside your job-search-tool folder by pressing Ctrl+S.
  • Add the following configuration code to job_search.py:
import requests
import pandas as pd

# Configuration
API_KEY = "your-rapidapi-key-here"
API_HOST = "jsearch.p.rapidapi.com"

SEARCH_QUERY = "data analyst"
SEARCH_LOCATION = "San Antonio, Texas"
EMPLOYMENT_TYPE = "FULLTIME"
NUM_PAGES = 3

# API request setup
headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": API_HOST
}

What does this code do?

  • import requests brings in the library that sends HTTP requests to the API.
  • import pandas as pd loads the data analysis library with the shorthand pd (a common convention).
  • API_KEY and API_HOST tell your script which API to connect to and how to authenticate.
  • SEARCH_QUERY, SEARCH_LOCATION, and the other constants define what jobs you are looking for.
  • headers is a dictionary that gets sent with every API request to prove your identity to RapidAPI.
  • Replace your-rapidapi-key-here with the actual API key you copied from RapidAPI. Keep the quotes around it.
  • Save job_search.py by pressing Ctrl+S.
  • Confirm the file appears in the VS Code Explorer sidebar on the left. You should see job_search.py listed under your job-search-tool folder.

File saved in the wrong location?

  • If job_search.py does not appear in the Explorer sidebar, you may have saved it outside the project folder. Delete the misplaced file, then right-click in the Explorer sidebar and select New File to create it in the correct location.
  • Make sure the file ends with .py (not .py.txt). VS Code should show a Python icon next to the filename.

Help me create and save a Python file in the correct project folder in VS Code.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file with Ctrl+S and you are ready to move on.

ⓧ I'd like to double check the full code

Here is the complete job_search.py file so far. Make sure your code matches this exactly (except for your actual API key in place of the placeholder).

import requests
import pandas as pd

# Configuration
API_KEY = "your-rapidapi-key-here"
API_HOST = "jsearch.p.rapidapi.com"

SEARCH_QUERY = "data analyst"
SEARCH_LOCATION = "San Antonio, Texas"
EMPLOYMENT_TYPE = "FULLTIME"
NUM_PAGES = 3

# API request setup
headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": API_HOST
}

Your libraries are installed and your script knows how to connect to the JSearch API. Next up, you will write the functions that actually send the search request and filter the results into something useful.

Query the API and Filter Results

Your configuration is set and your API key is ready. Now it's time to write the code that actually talks to the JSearch API and pulls back real job listings.

In this step, you'll write two functions. The first sends a request to the API with your search criteria. The second takes the raw response and extracts only the fields you care about.

In this step, get ready to:
  • Write the API query function that fetches job listings.
  • Write the filtering function that extracts relevant fields.
  • Run the script and verify results print to the terminal.
Write the search_jobs() function

An API works like a waiter at a restaurant. You send it a request describing what you want, and it brings back data from the kitchen (the server). Your function needs to send a GET request to the JSearch search endpoint with the right parameters.

  • In job_search.py, scroll to the bottom of the file (below the headers dictionary) and add the search_jobs() function by pasting this code:
def search_jobs():
    """Query the JSearch API for job listings."""
    url = "https://jsearch.p.rapidapi.com/search"
    params = {
        "query": f"{SEARCH_QUERY} in {SEARCH_LOCATION}",
        "page": "1",
        "num_pages": str(NUM_PAGES),
        "date_posted": "month",
        "remote_jobs_only": "false"
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code != 200:
        print(f"Error: API returned status code {response.status_code}")
        print(response.text)
        return []

    data = response.json()
    return data.get("data", [])

What does this code do?

  • url points to the JSearch /search endpoint, which aggregates job listings from LinkedIn, Indeed, Glassdoor, and ZipRecruiter.
  • params is a dictionary of search filters. The query combines your job title and location into a single search string. date_posted limits results to the last month so you only see fresh listings.
  • requests.get() sends the HTTP GET request. If the API returns an error (anything other than status code 200), the function prints the error and returns an empty list.
  • data.get("data", []) pulls out the list of job objects from the JSON response. The JSearch API nests all job results inside a data key.
  • Save job_search.py.

You won't see a change yet. The next function processes the raw data this function returns.

Write the filter_jobs() function

The API returns over 40 data points per job listing. Most of those are irrelevant for a quick job hunt. Your filtering function will extract only the fields that matter: title, company, location, salary, job type, date posted, and application link.

  • Below the search_jobs() function, add the filter_jobs() function by pasting this code:
def filter_jobs(raw_jobs):
    """Extract relevant fields from each job listing."""
    filtered = []

    for job in raw_jobs:
        filtered.append({
            "Job Title": job.get("job_title", "N/A"),
            "Company": job.get("employer_name", "N/A"),
            "Location": f"{job.get('job_city', 'N/A')}, {job.get('job_state', 'N/A')}",
            "Min Salary": job.get("job_min_salary"),
            "Max Salary": job.get("job_max_salary"),
            "Job Type": job.get("job_employment_type", "N/A"),
            "Date Posted": job.get("job_posted_at_datetime_utc", "N/A")[:10] if job.get("job_posted_at_datetime_utc") else "N/A",
            "Apply Link": job.get("job_apply_link", "N/A")
        })

    return filtered

What does this code do?

  • The function loops through each job in raw_jobs and builds a clean dictionary with only the fields you need.
  • job.get("key", "N/A") safely pulls a value from the job data. If the field is missing, it defaults to "N/A" instead of crashing.
  • The Location field combines job_city and job_state into a readable format like "San Antonio, Texas".
  • The Date Posted field uses [:10] to grab just the date portion (first 10 characters) from a full timestamp string.
  • Save job_search.py.

Seeing a red underline or syntax error?

  • Make sure the filter_jobs function starts at the same indentation level as search_jobs (no extra spaces before def).
  • Check that there is a blank line separating the two functions.
  • Verify your quotes match. The f-string inside Location uses single quotes inside double quotes.

Help me fix a syntax error in my filter_jobs function.

Run the script to verify results

Your two functions are written but nothing calls them yet. You'll add temporary test code to the bottom of the file to verify everything works before building the full export in the next step.

  • At the very bottom of job_search.py, add this temporary test code:
# Temporary test - remove after verifying
raw = search_jobs()
print(f"Found {len(raw)} raw listings")

jobs = filter_jobs(raw)
for job in jobs[:3]:
    print(job)
  • Save job_search.py.
  • Run the script by entering this command in the terminal:
python job_search.py

You should see output showing how many listings were found, followed by 3 sample job dictionaries printed to the terminal. Each dictionary includes keys like Job Title, Company, and Apply Link.

Getting an error or no results?

  • If you see Error: API returned status code 403, your API key is incorrect. Return to the RapidAPI JSearch page and copy the key again from the x-rapidapi-key field in the code snippet area.
  • If you see Found 0 raw listings, try changing your SEARCH_QUERY to a broader term like "analyst" or change SEARCH_LOCATION to a larger metro area.
  • If you see ModuleNotFoundError: No module named 'requests', your virtual environment is not activated. Run .venv\Scripts\activate first, then try again.

Help me troubleshoot my JSearch API call that is returning an error.

  • Once you see job listings printed successfully, remove the temporary test code (the last 6 lines starting from the # Temporary test comment).
  • Save job_search.py.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file after removing the test code.

ⓧ I'd like to double check the full code

Here is the complete job_search.py file as it should look at the end of this step:

import requests
import pandas as pd

# Configuration
API_KEY = "your-rapidapi-key-here"
API_HOST = "jsearch.p.rapidapi.com"

SEARCH_QUERY = "data analyst"
SEARCH_LOCATION = "San Antonio, Texas"
EMPLOYMENT_TYPE = "FULLTIME"
NUM_PAGES = 3

# API request setup
headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": API_HOST
}


def search_jobs():
    """Query the JSearch API for job listings."""
    url = "https://jsearch.p.rapidapi.com/search"
    params = {
        "query": f"{SEARCH_QUERY} in {SEARCH_LOCATION}",
        "page": "1",
        "num_pages": str(NUM_PAGES),
        "date_posted": "month",
        "remote_jobs_only": "false"
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code != 200:
        print(f"Error: API returned status code {response.status_code}")
        print(response.text)
        return []

    data = response.json()
    return data.get("data", [])


def filter_jobs(raw_jobs):
    """Extract relevant fields from each job listing."""
    filtered = []

    for job in raw_jobs:
        filtered.append({
            "Job Title": job.get("job_title", "N/A"),
            "Company": job.get("employer_name", "N/A"),
            "Location": f"{job.get('job_city', 'N/A')}, {job.get('job_state', 'N/A')}",
            "Min Salary": job.get("job_min_salary"),
            "Max Salary": job.get("job_max_salary"),
            "Job Type": job.get("job_employment_type", "N/A"),
            "Date Posted": job.get("job_posted_at_datetime_utc", "N/A")[:10] if job.get("job_posted_at_datetime_utc") else "N/A",
            "Apply Link": job.get("job_apply_link", "N/A")
        })

    return filtered

Your script can now pull real job data from across the web and extract the fields that matter. Next up, you'll turn those results into a clean Excel spreadsheet you can use for your job search.

Export to Excel and Format the Spreadsheet

In the previous step, you connected to the JSearch API and built a filtering function that extracts the fields you care about from each listing.

Now it is time to turn those filtered results into something you can actually use. In this step, you will convert your job data into a pandas DataFrame, export it to an Excel spreadsheet, and wire everything together with a main() function that runs the full pipeline end-to-end.

In this step, get ready to:
  • Build an export function that writes job data to a formatted Excel file.
  • Write a main function that orchestrates the entire search-filter-export workflow.
  • Run the complete script and verify your spreadsheet.
Build the Excel export function

Your filtered job data is currently a Python list of dictionaries. To turn it into a spreadsheet, you will create a DataFrame (a table structure from pandas) and write it to an .xlsx file using the openpyxl engine.

  • In job_search.py, scroll to the bottom of your file (below the filter_jobs function) and add the export_to_excel function by copying this code:
def export_to_excel(jobs):
    """Export job listings to an Excel spreadsheet."""
    # Convert the list of dictionaries into a pandas DataFrame
    df = pd.DataFrame(jobs)

    # Write the DataFrame to an Excel file with formatting
    with pd.ExcelWriter("data_analyst_jobs.xlsx", engine="openpyxl") as writer:
        df.to_excel(writer, index=False, sheet_name="Jobs")

        # Auto-size columns for readability
        worksheet = writer.sheets["Jobs"]
        for column in worksheet.columns:
            max_length = 0
            column_letter = column[0].column_letter
            for cell in column:
                if cell.value:
                    max_length = max(max_length, len(str(cell.value)))
            adjusted_width = min(max_length + 2, 50)
            worksheet.column_dimensions[column_letter].width = adjusted_width

    print(f"Exported {len(df)} jobs to data_analyst_jobs.xlsx")

What does this code do?

This function handles the entire export process in three stages:

  • pd.DataFrame(jobs) converts your list of job dictionaries into a tabular DataFrame. Each dictionary key becomes a column header.
  • pd.ExcelWriter with engine="openpyxl" creates the Excel file. The index=False parameter removes the row numbers that pandas adds by default.
  • The column-sizing loop measures the longest value in each column and sets the width accordingly. The min(..., 50) cap prevents any single column from becoming too wide.
  • Save job_search.py.

You will not see a change yet because nothing calls this function. The next chunk wires it up.

Add the main function to run everything

A main() function is the entry point that orchestrates each step of your script: searching, filtering, and exporting.

  • Below the export_to_excel function in job_search.py, add the main() function and the entry point guard by copying this code:
def main():
    # Print a status message so you know the script is running
    print(f"Searching for '{SEARCH_QUERY}' jobs in {SEARCH_LOCATION}...")
    raw_jobs = search_jobs()

    # Stop early if nothing came back
    if not raw_jobs:
        print("No jobs found. Check your API key and search parameters.")
        return

    # Filter and export the results
    print(f"Found {len(raw_jobs)} raw listings. Filtering...")
    jobs = filter_jobs(raw_jobs)

    export_to_excel(jobs)
    print("Done! Open data_analyst_jobs.xlsx to see your results.")


if __name__ == "__main__":
    main()

What does this code do?

The main() function runs three steps in order: call the API, filter the raw data, and export to Excel. If the API returns no results, the script prints a helpful message and exits early.

The if __name__ == "__main__": guard at the bottom tells Python to run main() only when you execute the file directly. This is standard practice for Python scripts.

  • Save job_search.py.

Seeing a syntax error when you save?

  • Make sure you have a blank line between the end of export_to_excel and the start of def main():. Python requires spacing between function definitions.
  • Check that if __name__ == "__main__": is at the very bottom of the file with no indentation.

Ask for help: I'm getting a syntax error in job_search.py after adding the main function. Can you help me debug?

Run the complete script and verify results

Everything is wired up. Time to run the script and see your job data exported to a real spreadsheet.

  • Make sure your virtual environment is still active (you should see (.venv) at the start of your terminal prompt).
  • Run the script by entering this command in the VS Code terminal:
python job_search.py
  • You should see output similar to this in your terminal:
Searching for 'data analyst' jobs in San Antonio, Texas...
Found 30 raw listings. Filtering...
Exported 30 jobs to data_analyst_jobs.xlsx
Done! Open data_analyst_jobs.xlsx to see your results.

What should I see?

The exact number of jobs will vary depending on what is currently listed on job sites. You might see anywhere from 10 to 30 listings. As long as you see a positive number and the "Exported" message, your script is working correctly.

  • Confirm the Excel file was created by running:
ls
  • You should see data_analyst_jobs.xlsx in the output alongside job_search.py and your .venv folder.
  • Open data_analyst_jobs.xlsx in Excel (or any spreadsheet app). You should see columns for Job Title, Company, Location, Min Salary, Max Salary, Job Type, Date Posted, and Apply Link.

No jobs found or seeing an error?

  • If you see "No jobs found", double check that your API key in the API_KEY variable matches the key shown on your RapidAPI dashboard.
  • If you see "Error: API returned status code 403", your RapidAPI subscription to JSearch may not be active. Return to the JSearch API page on RapidAPI and confirm you are subscribed to the free BASIC plan.
  • If you see a ModuleNotFoundError, your virtual environment may not be active. Run .venv\Scripts\activate and try again.

Ask for help: My job_search.py script isn't producing results or is showing an error. Can you help me troubleshoot?

✔️ Awesome, I've got everything!

Great. Double check you have saved job_search.py and that data_analyst_jobs.xlsx is sitting in your job-search-tool folder.

ⓧ I'd like to double check the full code

Here is the complete job_search.py file. Compare it against yours to make sure everything matches:

import requests
import pandas as pd

# Configuration
API_KEY = "your-rapidapi-key-here"
API_HOST = "jsearch.p.rapidapi.com"

SEARCH_QUERY = "data analyst"
SEARCH_LOCATION = "San Antonio, Texas"
EMPLOYMENT_TYPE = "FULLTIME"
NUM_PAGES = 3

# API request setup
headers = {
    "x-rapidapi-key": API_KEY,
    "x-rapidapi-host": API_HOST
}


def search_jobs():
    """Query the JSearch API for job listings."""
    url = "https://jsearch.p.rapidapi.com/search"
    params = {
        "query": f"{SEARCH_QUERY} in {SEARCH_LOCATION}",
        "page": "1",
        "num_pages": str(NUM_PAGES),
        "date_posted": "month",
        "remote_jobs_only": "false"
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code != 200:
        print(f"Error: API returned status code {response.status_code}")
        print(response.text)
        return []

    data = response.json()
    return data.get("data", [])


def filter_jobs(raw_jobs):
    """Extract relevant fields from each job listing."""
    filtered = []

    for job in raw_jobs:
        filtered.append({
            "Job Title": job.get("job_title", "N/A"),
            "Company": job.get("employer_name", "N/A"),
            "Location": f"{job.get('job_city', 'N/A')}, {job.get('job_state', 'N/A')}",
            "Min Salary": job.get("job_min_salary"),
            "Max Salary": job.get("job_max_salary"),
            "Job Type": job.get("job_employment_type", "N/A"),
            "Date Posted": job.get("job_posted_at_datetime_utc", "N/A")[:10] if job.get("job_posted_at_datetime_utc") else "N/A",
            "Apply Link": job.get("job_apply_link", "N/A")
        })

    return filtered


def export_to_excel(jobs):
    """Export job listings to an Excel spreadsheet."""
    df = pd.DataFrame(jobs)

    with pd.ExcelWriter("data_analyst_jobs.xlsx", engine="openpyxl") as writer:
        df.to_excel(writer, index=False, sheet_name="Jobs")

        worksheet = writer.sheets["Jobs"]
        for column in worksheet.columns:
            max_length = 0
            column_letter = column[0].column_letter
            for cell in column:
                if cell.value:
                    max_length = max(max_length, len(str(cell.value)))
            adjusted_width = min(max_length + 2, 50)
            worksheet.column_dimensions[column_letter].width = adjusted_width

    print(f"Exported {len(df)} jobs to data_analyst_jobs.xlsx")


def main():
    print(f"Searching for '{SEARCH_QUERY}' jobs in {SEARCH_LOCATION}...")
    raw_jobs = search_jobs()

    if not raw_jobs:
        print("No jobs found. Check your API key and search parameters.")
        return

    print(f"Found {len(raw_jobs)} raw listings. Filtering...")
    jobs = filter_jobs(raw_jobs)

    export_to_excel(jobs)
    print("Done! Open data_analyst_jobs.xlsx to see your results.")


if __name__ == "__main__":
    main()

Your job search tool is fully functional. You can re-run this script anytime to get fresh listings. Next up, tackle the Secret Mission to add salary analysis that identifies the highest-paying roles in your results.

Secret mission

Add Salary Analysis

Your job search tool finds listings, but which ones pay the best? In this secret mission, you'll add salary analysis that calculates averages, identifies the top-paying roles, and exports a summary sheet to your spreadsheet.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely on your local machine and uses a free API tier, so there are no ongoing costs. Decide whether to keep your resources for future use or delete them entirely.

Resources you used:

  • Local project folder job-search-tool on your Desktop (contains job_search.py, data_analyst_jobs.xlsx, and the .venv virtual environment).
  • RapidAPI account (free BASIC plan, no credit card on file, no charges).

Keep everything running

No action needed. Choose this if you plan to re-run your script to get fresh job listings or modify the search parameters for different roles.

  • Your script and spreadsheet stay on your local machine at no cost.
  • Your RapidAPI free tier renews monthly (200 requests/month) so you can re-run anytime.
  • Python and VS Code remain installed and available for future projects.

Pause - I'll come back to this later

Since everything is local and the API tier is free, there is nothing to pause. Your files sit idle on your Desktop until you return.

  • You can deactivate your virtual environment by running the command below in your VS Code terminal:
deactivate
  • This frees the terminal from the virtual environment, but your project files remain untouched.

Delete - I don't want to use this again

Remove all project files and optionally delete your RapidAPI account to start completely fresh.

  • Deactivate your virtual environment first by running:
deactivate
  • Delete the project folder by running:
cd ~/Desktop
rmdir /s /q job-search-tool
  • To delete your RapidAPI account, go to rapidapi.com and click your user icon in the upper right corner.
  • Select User Settings.
  • Under Delete Current User, click Delete.
  • Enter your email address to confirm, then click Delete again. This is permanent and removes all your API subscriptions and usage data.

Nice Work!

Nice Work!

Nice work! You just built a Python automation tool that pulls real job listings from across the internet and delivers them to your desktop in a clean, organized spreadsheet.

You've learned how to:

  • Connected to the JSearch API to pull live job listings aggregated from LinkedIn, Indeed, Glassdoor, and ZipRecruiter.
  • Written a Python script that queries, filters, and processes real-world job data using HTTP requests and JSON parsing.
  • Exported structured results to an Excel spreadsheet using pandas DataFrames, ready for your job hunt.
  • Secret Mission: Added salary analysis to calculate average, min, and max salaries and highlight the top-paying data analyst roles near San Antonio.

Ready to quiz yourself?