Post

Automating Job Application Processes with Python

In today’s fast-paced world, automating repetitive tasks can save time and reduce errors. If you’re a job seeker, keeping up with new job postings and crafting customised cover letters can be time-consuming. In this blog post, I’ll walk you through a Python script that automates these processes by scraping job listings from Seek, generating cover letters using OpenAI’s API, and saving everything in an organised manner.

Prerequisites

Before diving into the code, make sure you have the following installed:

  • Python 3.x
  • Requests Library (pip install requests)
  • BeautifulSoup Library (pip install beautifulsoup4)
  • OpenAI Library (pip install openai)

Additionally, you’ll need an OpenAI API key to generate the cover letters.

Script Overview

The script performs the following tasks:

  • Scrapes job listings from a specified Seek URL.
  • Extracts job details such as the job title, description, and unique job ID.
  • Generates a customised cover letter for each job using OpenAI’s GPT model.
  • Saves job details and cover letters in organised directories.
  • Tracks processed jobs to avoid duplicating efforts on the same job posting.

The Code

Here’s the complete script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import requests
from bs4 import BeautifulSoup
import os
import re
import openai
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# Configuration
seek_url = "https://www.seek.com.au/jobs-in-information-communication-technology/management/in-All-Gold-Coast-QLD"
email_sender = '[email protected]'
email_password = 'password'
email_receiver = '[email protected]'
email_subject = "New Senior IT Manager Job Listings in Gold Coast"
smtp_host = 'smtp.example.com'  # Replace with your SMTP host
smtp_port = 25  # Replace with your SMTP port
jobs_directory = 'job_listings'
cover_letter_directory = 'cover_letters'
processed_jobs_file = 'processed_jobs.txt'
openai.api_key = 'openai_gpt_api_key'  # Set your OpenAI API key here

# Ensure directories exist
os.makedirs(jobs_directory, exist_ok=True)
os.makedirs(cover_letter_directory, exist_ok=True)

# Function to clean and create a safe filename
def clean_filename(title):
    title = re.sub(r'[^a-zA-Z0-9_\s]', '', title)
    return title.replace(' ', '_')

# Function to extract unique job ID from URL
def extract_job_id(job_link):
    match = re.search(r'job/(\d+)', job_link)
    return match.group(1) if match else None

# Function to save job content to a file
def save_job_to_file(job_title, job_content, job_id):
    filename = f"{clean_filename(job_title)}_{job_id}.txt"
    with open(os.path.join(jobs_directory, filename), 'w', encoding='utf-8') as file:
        file.write(job_content)
    return filename

# Function to scrape job content from the job ad page
def scrape_job_content(job_link):
    response = requests.get(job_link)
    soup = BeautifulSoup(response.text, 'html.parser')
    job_description = soup.find('div', {'data-automation': 'jobAdDetails'})  # Adjust this selector if necessary
    if job_description:
        return job_description.get_text(separator="\n").strip()
    return "No job description found."

# Function to check jobs on Seek
def check_seek_jobs(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    job_listings = soup.find_all('a', {'data-automation': 'jobTitle'})  # Adjust this selector if necessary
    return job_listings

# Function to generate a cover letter using ChatGPT API
def generate_cover_letter(job_content):
    prompt = (
        "From the below, build a compact brief cover letter that has been written "
        "by a Senior Systems Administrator with experience managing a team for over 5 years.\n\n"
        + job_content
    )
    try:
        response = openai.ChatCompletion.create(
            model="gpt-4o",  # or "gpt-3.5-turbo" if you have access to GPT-4
            messages=[{"role": "user", "content": prompt}],
            max_tokens=300  # Adjust this value if you need a longer cover letter
        )
        return response['choices'][0]['message']['content'].strip()
    except Exception as e:
        print(f"Error generating cover letter: {e}")
        return None

# Function to load processed jobs from file
def load_processed_jobs():
    if os.path.exists(processed_jobs_file):
        with open(processed_jobs_file, 'r') as file:
            return set(line.strip() for line in file.readlines())
    return set()

# Function to save processed job IDs to file
def save_processed_job(job_id):
    with open(processed_jobs_file, 'a') as file:
        file.write(f"{job_id}\n")

# Function to send email with new job listings
def send_email(new_jobs):
    msg = MIMEMultipart()
    msg['From'] = email_sender
    msg['To'] = email_receiver
    msg['Subject'] = email_subject
    
    body = "New Senior IT Manager Job Listings:\n\n" + "\n".join(new_jobs)
    msg.attach(MIMEText(body, 'plain'))
    
    try:
        server = smtplib.SMTP(smtp_host, smtp_port)
        server.starttls()
        server.login(email_sender, email_password)
        server.sendmail(email_sender, email_receiver, msg.as_string())
        server.quit()
        print("Email sent successfully.")
    except Exception as e:
        print(f"Error sending email: {e}")

# Main script to search for jobs, scrape content, generate cover letters, and email new jobs
def main():
    processed_jobs = load_processed_jobs()
    jobs = check_seek_jobs(seek_url)
    new_jobs = []
    
    if jobs:
        for job in jobs[:20]:  # Limit to first 5 jobs
            job_title = job.text.strip()
            job_link = job['href']
            if not job_link.startswith('http'):
                job_link = "https://www.seek.com.au" + job_link
            
            job_id = extract_job_id(job_link)
            
            # Skip jobs that have already been processed
            if job_id is None or job_id in processed_jobs:
                continue
            
            job_content = scrape_job_content(job_link)
            job_filename = save_job_to_file(job_title, job_content, job_id)
            
            cover_letter = generate_cover_letter(job_content)
            if cover_letter:
                cover_letter_filename = os.path.join(cover_letter_directory, f"Cover_Letter_{job_title}_{job_id}.txt")
                with open(cover_letter_filename, 'w', encoding='utf-8') as file:
                    file.write(cover_letter)
                new_jobs.append(f"{job_title}\n{job_link}\n")
                print(f"Cover letter generated and saved as {cover_letter_filename}")
                
            # Mark this job as processed
            save_processed_job(job_id)
    
    if new_jobs:
        send_email(new_jobs)
    else:
        print("No new jobs found.")

if __name__ == "__main__":
    main()

Modules Install

1
pip install requests beautifulsoup4 openai==0.28

How It Works

  1. Directory Management: The script ensures that directories for saving job listings and cover letters exist. If not, they are created.
  2. Job Scraping: It uses BeautifulSoup to scrape job titles and links from the specified Seek URL.
  3. Job Content Extraction: Once a job is identified, the script fetches and processes the full job description.
  4. Cover Letter Generation: The script then interacts with OpenAI’s GPT model to generate a tailored cover letter based on the job description.
  5. File Management: The job details and cover letters are saved in neatly organised text files, and processed job IDs are stored to avoid duplicates in future runs.

Customisation Tips

  • Modify the Seek URL: Change the seek_url variable to target different job categories or locations.
  • Customise the Cover Letter Prompt: Adjust the prompt in the generate_cover_letter function to suit your profile better.

Final Thoughts

This script can be a powerful tool for job seekers in the IT industry, allowing them to streamline their application process and ensure they don’t miss out on opportunities. With a bit of tweaking, it can be adapted for other job boards and industries.

Remember to keep your OpenAI API key secure and never hard-code sensitive information directly into your scripts. Happy job hunting!

This post is licensed under CC BY 4.0 by the author.