Automating Job Application tasks

Since graduating, I have applied for several jobs in my area. For the past several years I have used the same old system for keeping track of all job applications:

Step 1: Create a new directory

  • Directory name starts with an incrementing integer, with the method applied and job title appended to it
  • Format {index}-{method_applied}-{job_title}
  • Example 01-Indeed-HR-Manager indicates that this is the first application of the month, applied on the Indeed website, and the job title is HR Manager.

Step 2: Store data inside directory

  • Screenshot the application, and any other relevant webpages
  • Include all job file attachments, DOCX/PDF etc.
  • Backup any questions answered to markdown.

Doing it this way has worked for a while, but now I wish to improve upon my original method by collecting more data, automating tasks and implement cool features. Introducing project Cadmic.

Webpage displays a list of my job applications.
List items of My Job Applications (fake data)

About Cadmic

When applying for jobs, I discovered early on that managing my applications from multiple websites was tedious in addition to effectively cross-referencing jobs.

Cadmic is a web app used to store all your job applications in one place and to automate tasks such as archival. Project is written in Laravel 6, design is simplistic, taking some inspiration from Reed and is responsive thanks to Bootstrap.

Although the project is new (about a week old), some of the automated features included:

  • Full-page screenshot of the online job application
  • Ping archive.org to save a HTML copy of the job submission
  • Export all data from job application, convert text to Markdown and put into a Zip archive for instant download.

Features

This section will discuss certain features in-depth and outline API’s used.

Auto-complete location

During previous projects ensuring address consistency required use of an API, because you cannot rely on humans to input consistent addresses. I chose to try a different API this time, Algolia Places.

I found this API good for basic use, however it sometimes lacked precision during lookup and often had difficulty finding a specific area. For this project, the address does not require precise location data.

WYSIWYG

Looking at job sites, I noticed that organisations/recruiters poorly format job descriptions. I could not ignore this for my own sanity, so I researched a few WYSIWYG’s.

New application page, displays form inputs and WYSIWYG, Summernote.
New job application UI

Aim was to find a WYSIWYG that could accept copy/paste and would strip HTML tags/classes from a given job description. I found Summernote to be a great option, very customisable and free.

Archive.org

You may not have heard the name archive.org, but maybe Wayback machine. This website is great for looking at old archived versions of websites that you love. Have a look at YouTube from April 28th 2005, when it was first launched as a dating website.

Making a request to archive.org to save the webpage was simple to achieve. While looking at the save webpage feature I observed how it made this action. Try this example for yourself, you will notice that it redirects you to the archived URL.

Doing it programmatically is a little different because you will need to acquire that URL using a different method. In this example I am using a queue in Laravel. Queues help defer the processing of time-consuming tasks.

// Additional imports here...

use App\JobApplication;
use GuzzleHttp\Client;

class ArchiveWebpage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $j;

    /**
    * Create a new job instance.
    *
    * @return void
    */
    public function __construct(JobApplication $job)
    {
        $this->j = $job;
    }

    /**
    * Execute the job.
    *
    * @return void
    */
    public function handle()
    {
        // Assign job
        $job = $this->j;

        // Assign job application URL to string
        $path = "https://web.archive.org/save/$job->url";

        // Init Guzzle
        $client = new Client();
        
        try 
        {
            // Get specific header from the response
            $res = $client->get($path)->getHeader('Content-Location')[0];

            // Assign and append header to URL
            $job->url_archived = "https://web.archive.org$res";

            // Update job with new changes
            $job->update();
        } 
        catch (\Throwable $th)
        {
            throw $th;
        }
    }
}

When the task is dispatched, the specific job application will be passed to the queue.

  1. Line 32 I append the job URL (the URL of the job application) to the archive.org URL.
  2. Attempt to get a specific header from the response Content-Location. This header has part of the archived URL.
  3. Line 43 I complete the URL, assign it to the model then save changes.

Favicon “finder”

During development I thought it would look nice to include a favicon next to the job site URL. I pondered over the idea to create a script that would scrape the favicon, but since it is not an original idea, I researched a solution first. Solution(s) can be found here.

<!-- Retrieve favicon -->
<img src="https://www.google.com/s2/favicons?domain=https://stackoverflow.com" alt="Favicon" loading="lazy">

Full-page screenshot

When initially developing Cadmic, I knew that the full-page screenshot feature would probably be a headache, so instead of solving the problem, I offered users the ability to upload a screenshot instead.

This method worked however, I wanted to automate the task so that I could offer consistent full-page screenshots, without the need to rely on users, especially those who are using mobile/tablets, often lacking the ability to take full-page screenshots.

This issue would probably require some sort of headless browser to screenshot and handle the loading of JavaScript and web fonts. When researching, I found this open source API, Screenly running on Laravel using PhantomJS to capture the screenshot.

When using Screenly, I pass my $job->url, it returns a path to download the screenshot in JSON, download the image, assign it a random name, store the file and link to it in database. Simple.

New features to include

So far, I have outlined some of the features in the web app but I have a few outstanding. In no particular order, here is a list of features in-progress that are my highest priority.

  • Search for:
    • Job title
    • Keywords in description
    • Date applied/posted
    • Salary
    • Name of the recruiter/organisation who posted the application
  • Save complete webpage Store the HTML/CSS/JS and archive it
  • Dashboard Include graphs and stats of applications
Single view of job application
Single view of job application

Conclusion

So far, I am happy with how the project is going. Cadmic does the job well and is superior to my current setup. Some of the above features are currently in-progress. This article will be updated as I go along.

If you have any ideas, interesting features, or comments, let me know.