<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joerg Rech</title>
    <description>The latest articles on DEV Community by Joerg Rech (@joerg_rech).</description>
    <link>https://dev.to/joerg_rech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1115404%2F10b668a8-6774-4656-8094-d4ce5418ce15.jpg</url>
      <title>DEV Community: Joerg Rech</title>
      <link>https://dev.to/joerg_rech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joerg_rech"/>
    <language>en</language>
    <item>
      <title>Exploring Salary Trends with JavaScript: A Spring Break Project 🕵️‍♂️📊</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Mon, 03 Mar 2025 11:14:24 +0000</pubDate>
      <link>https://dev.to/joerg_rech/exploring-salary-trends-with-javascript-a-spring-break-project-1h64</link>
      <guid>https://dev.to/joerg_rech/exploring-salary-trends-with-javascript-a-spring-break-project-1h64</guid>
      <description>&lt;p&gt;Use your Spring Break to explore a fascinating project that combines coding skills with real-world data analysis. By working with a Job Postings API, you'll learn to fetch and analyze salary data for software developers using JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jobdatafeeds.com/blog/post/hope-springs-eternal-as-do-salaries-a-spring-break-project" rel="noopener noreferrer"&gt;This tutorial&lt;/a&gt; involves:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Get started with &lt;code&gt;Node.js&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt;. Obtain the API key from RapidAPI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Interaction:&lt;/strong&gt; Use &lt;code&gt;node-fetch&lt;/code&gt; to retrieve job postings with salary details. Filter and process the data to extract relevant insights.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Statistical Analysis:&lt;/strong&gt; Calculate average, high, and low salaries. Consider factors influencing these figures, such as location and experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portfolio Development:&lt;/strong&gt; Document your process and results, and add this project to your portfolio to demonstrate your analytical skills.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As a tutorial it helps you to develop practical coding skills while gaining insights into the tech job market. It's a great way to enhance your portfolio and prepare for future career opportunities.&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://jobdatafeeds.com/blog/post/hope-springs-eternal-as-do-salaries-a-spring-break-project" rel="noopener noreferrer"&gt;Hope Springs Eternal - As Do Salaries? A Spring Break Project&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>sideprojects</category>
      <category>salary</category>
      <category>datascience</category>
    </item>
    <item>
      <title>The Developer’s Guide to Automating Remote Job Alerts</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Tue, 25 Feb 2025 14:22:15 +0000</pubDate>
      <link>https://dev.to/joerg_rech/the-developers-guide-to-automating-remote-job-alerts-e7l</link>
      <guid>https://dev.to/joerg_rech/the-developers-guide-to-automating-remote-job-alerts-e7l</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Looking for a remote job as a developer can feel overwhelming. There are so many job boards, and checking them regularly takes time we don’t always have. What if we could automate this process?&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll use a Job Posting API on RapidAPI and Bash commands to fetch remote job postings, format them into a clean table, and set up a weekly email alert. By the end, we’ll have a simple yet powerful tool to keep us informed about new opportunities without the hassle of manual searches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Let’s start by setting up our environment. We’ll use Ubuntu or a similar Linux distribution for this tutorial. If you’re on Windows, you can use WSL or a virtual machine to follow along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a RapidAPI Account and Subscribing to the API
&lt;/h3&gt;

&lt;p&gt;First we need a RapidAPI account to access the job postings API - don’t worry, it’s free to sign up, and we’ll grab an API key once we’re logged in.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a RapidAPI Account&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://rapidapi.com/" rel="noopener noreferrer"&gt;RapidAPI&lt;/a&gt; and click on the &lt;strong&gt;Sign Up&lt;/strong&gt; button in the top-right corner.&lt;/li&gt;
&lt;li&gt;You can sign up using your email, Google account, or GitHub account. Follow the prompts to complete the registration process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Subscribe to the Job Postings API&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once logged in, you can visit the API’s page using this link: &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings" rel="noopener noreferrer"&gt;Daily International Job Postings API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;On the API’s page, you can read up on the API features and go to the &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings/pricing" rel="noopener noreferrer"&gt;Pricing section&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Basic&lt;/strong&gt; plan, which offers 25 free requests per month, with each request returning up to 10 job postings.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Subscribe&lt;/strong&gt; button and confirm your selection.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Get Your API Key&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After subscribing, navigate to the &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings/playground/apiendpoint_08913b1f-c22a-4ed3-9614-b0da71811631" rel="noopener noreferrer"&gt;Endpoints section&lt;/a&gt; on the API’s page.&lt;/li&gt;
&lt;li&gt;Look for the &lt;strong&gt;Headers&lt;/strong&gt; section in any endpoint example. You’ll see two required headers:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x-rapidapi-key&lt;/code&gt;: This is your unique &lt;strong&gt;API key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x-rapidapi-host&lt;/code&gt;: This should be set to &lt;code&gt;daily-international-job-postings.p.rapidapi.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copy your &lt;code&gt;x-rapidapi-key&lt;/code&gt; and &lt;strong&gt;keep it secure&lt;/strong&gt; - we’ll use it in our script to authenticate API requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that we’ve set up our RapidAPI account and subscribed to the Basic plan, we’re ready to start building our script to fetch and process remote job postings. Let’s move on to the next step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Required Bash Commands
&lt;/h3&gt;

&lt;p&gt;Next, we’ll install some command-line tools to make our lives easier. We’ll use &lt;code&gt;curl&lt;/code&gt; to fetch data from the API, &lt;code&gt;jq&lt;/code&gt; to process the JSON responses, and &lt;code&gt;ssmtp&lt;/code&gt; or &lt;code&gt;mailutils&lt;/code&gt; to send emails. If you don’t already have these installed, you'll need to run some quick command to get them set up. Additionally, we’ll configure &lt;code&gt;ssmtp&lt;/code&gt; with our email credentials so we can send the job postings directly to our inbox.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check if &lt;code&gt;curl&lt;/code&gt; is Installed&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;curl&lt;/code&gt; is a command-line tool for making HTTP requests. It’s commonly pre-installed on most Linux distributions, but let’s verify by running &lt;code&gt;curl --version&lt;/code&gt;. If you see version information, &lt;code&gt;curl&lt;/code&gt; is installed. If not, install it with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check if &lt;code&gt;jq&lt;/code&gt; is Installed&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;jq&lt;/code&gt; is a lightweight JSON processor that we’ll use to parse and format the API responses. Check if &lt;code&gt;jq&lt;/code&gt; is installed by running &lt;code&gt;jq --version&lt;/code&gt;. If it’s not installed, install it with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check if &lt;code&gt;ssmtp&lt;/code&gt; or &lt;code&gt;mailutils&lt;/code&gt; is Installed&lt;/strong&gt;&lt;br&gt;
We’ll use either &lt;code&gt;ssmtp&lt;/code&gt; or &lt;code&gt;mailutils&lt;/code&gt; to send emails from the command line. Check if &lt;code&gt;ssmtp&lt;/code&gt; is installed by running &lt;code&gt;ssmtp --version&lt;/code&gt;. If &lt;code&gt;ssmtp&lt;/code&gt; not installed, install it with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ssmtp
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;and if you want to use &lt;code&gt;mail&lt;/code&gt; check if &lt;code&gt;mailutils&lt;/code&gt; is installed by running &lt;code&gt;mail --version&lt;/code&gt;. If it’s not installed, install it with:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;mailutils
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Email Sending&lt;/strong&gt;&lt;br&gt;
If you’re using &lt;code&gt;mailutils&lt;/code&gt;, no additional configuration is required for basic usage. If you’re using &lt;code&gt;ssmtp&lt;/code&gt;, you’ll need to configure it with your email credentials. Open the configuration file in a text editor by running &lt;code&gt;sudo nano /etc/ssmtp/ssmtp.conf&lt;/code&gt; and add the following lines, replacing placeholders with your email provider’s SMTP settings (e.g., Gmail):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  root=your_email@gmail.com
  mailhub=smtp.gmail.com:587
  AuthUser=your_email@gmail.com
  AuthPass=your_email_password
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Save and exit the file (&lt;code&gt;Ctrl+O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;, &lt;code&gt;Ctrl+X&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, we’ll need a basic understanding of Bash scripting. If you’ve ever written or run a shell script, you’re good to go. If not, don’t worry - we’ll keep the code simple and explain each step as we go. By the end, we'll have a script that fetches remote job postings, formats them, and sends them to our email account at the end of the month. Let’s get everything set up so we can start building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the Job Posting API
&lt;/h2&gt;

&lt;p&gt;The Job Posting API, as documented at &lt;a href="https://api.techmap.io/" rel="noopener noreferrer"&gt;https://api.techmap.io/&lt;/a&gt;, provides comprehensive access to job postings aggregated from a wide range of sources, including career pages, job boards, job aggregators, and employment offices. The API allows users to search and filter job postings based on various parameters such as job title, skills, company, location, industry, and more. It supports advanced querying capabilities, including &lt;strong&gt;Boolean searches&lt;/strong&gt;, &lt;strong&gt;keyphrase searches&lt;/strong&gt;, and &lt;strong&gt;geographic filtering&lt;/strong&gt;, enabling precise and flexible job searches. The API returns results in JSON format, making it easy to integrate into applications for backfilling job boards, detailed analysis, company monitoring, or automated job agents.&lt;/p&gt;

&lt;p&gt;One of the key features of the API is its ability to handle complex queries with multiple parameters. For example, users can search for remote jobs in specific time zones, jobs in particular industries, or jobs requiring specific skills. The API also supports pagination, allowing users to retrieve job postings in manageable chunks, with each request returning up to 10 job postings per page. Additionally, the API provides metadata endpoints in higher subscription plans that offer statistics and distinct values for specific fields, such as workPlace or industry, which can be useful for analyzing trends or building filters in job search applications.&lt;/p&gt;

&lt;p&gt;The API is designed to be developer-friendly, with clear documentation and examples for each endpoint. It also includes structured data in JSON-LD format, which can be directly integrated into webpages to enhance visibility and indexing by search engines. Overall, the Job Posting API is a powerful tool for developers looking to build or enhance job search functionalities, offering a rich set of features and flexible querying options to meet various use cases.&lt;/p&gt;

&lt;p&gt;For our goal, we can use the &lt;code&gt;/api/v2/jobs/search&lt;/code&gt; endpoint with the following query parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;workPlace&lt;/code&gt; for filtering jobs posted based on the place of work (e.g., on-site, hybrid, or remote),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt; for selecting job for a specific position (e.g., developer) or technology (e.e., Javascript),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;language&lt;/code&gt; to constrain the search to job postings written in English, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;page&lt;/code&gt; to paginate through larger lists of jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fetching Job Postings from the API
&lt;/h2&gt;

&lt;p&gt;To fetch remote job postings for Java developers using the Job Posting API, we’ll construct a query that filters jobs based on specific criteria. The API allows us to search for jobs using parameters like &lt;code&gt;workPlace&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt;. For this tutorial, we’ll focus on remote jobs (&lt;code&gt;workPlace=remote&lt;/code&gt;) that mention Java (&lt;code&gt;title=Java&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;curl&lt;/code&gt; with the URL parameters, we’ll construct a &lt;code&gt;GET&lt;/code&gt; request that includes the API endpoint, query parameters directly in the URL, and the required headers for authentication. For example, to fetch remote Java developer jobs in February 2025, we’ll use the following &lt;code&gt;curl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search?dateCreated=2025-02&amp;amp;workPlace=remote&amp;amp;title=Java&amp;amp;page=1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: daily-international-job-postings.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_API_KEY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command fetches the first page of remote Java developer jobs in JSON format. The results will also return the amount of all jobs (in the &lt;code&gt;totalCount&lt;/code&gt; field) for this query that can be used for pagination (divide by 10). To retrieve more results, we can loop through additional pages by incrementing the &lt;code&gt;page&lt;/code&gt; parameter (e.g., &lt;code&gt;page=2&lt;/code&gt;, &lt;code&gt;page=3&lt;/code&gt;, etc.). The response can then be processed further to extract and format the job postings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the full Script
&lt;/h3&gt;

&lt;p&gt;Finally, we’ll create the script that connects to the Job Postings API, queries for remote job postings, and stores the results in a file. To stay within the free tier of the subscription plan, the script will loop through up to 25 pages, fetching a maximum of 250 job postings. These results are then combined into a single JSON file, which will later be reformatted and sent via email to keep you updated on new job opportunities.&lt;/p&gt;

&lt;p&gt;The script leverages &lt;code&gt;curl&lt;/code&gt; to make HTTP requests and &lt;code&gt;jq&lt;/code&gt; to parse and manipulate the JSON responses. It iterates through multiple pages, retrieving up to 10 job postings per page and appending them to a combined JSON array. Once all pages are processed, the aggregated job postings are saved to a file named &lt;code&gt;jobs.json&lt;/code&gt;. This ensures you have a structured, up-to-date list of remote job opportunities ready for further processing.&lt;/p&gt;

&lt;p&gt;After fetching and formatting the job postings, the next step is to send this information to your email in a clean, readable table. Using &lt;code&gt;jq&lt;/code&gt;, we’ll extract key fields such as the date posted, job title, company, and URL. These details are then formatted into an HTML table for improved readability and sent to the specified email address.&lt;/p&gt;

&lt;p&gt;To get started, create a script named &lt;code&gt;fetch_jobs.sh&lt;/code&gt; and insert the code provided below. Before running the script, ensure you set your API key in the &lt;code&gt;RAPIDAPI_KEY&lt;/code&gt; variable and your email address in &lt;code&gt;EMAIL_RECIPIENT&lt;/code&gt;. Keep in mind that the free tier allows only 25 requests per month, so adjust your query parameters carefully to avoid exceeding this limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define general values&lt;/span&gt;
&lt;span class="nv"&gt;EMAIL_RECIPIENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your_email@gmail.com'&lt;/span&gt;

&lt;span class="c"&gt;# Define the API values&lt;/span&gt;
&lt;span class="nv"&gt;RAPIDAPI_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;My-RapidAPI-API-Key &lt;span class="c"&gt;# Can be defined outside the script but needs special handling for the cronjob&lt;/span&gt;
&lt;span class="nv"&gt;API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search"&lt;/span&gt;
&lt;span class="nv"&gt;HEADERS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-RapidAPI-Key: &lt;/span&gt;&lt;span class="nv"&gt;$RAPIDAPI_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-RapidAPI-Host: daily-international-job-postings.p.rapidapi.com"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# REQUEST_LIMIT=25 # if calling it monthly (free requests)&lt;/span&gt;
&lt;span class="nv"&gt;REQUEST_LIMIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="c"&gt;# for testing purposes&lt;/span&gt;
&lt;span class="nv"&gt;CURRENT_YEAR_MONTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y-%m"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Initialize an empty array to store all job postings&lt;/span&gt;
&lt;span class="nv"&gt;ALL_JOBS&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;span class="nv"&gt;MAX_PAGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nv"&gt;PAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt; PAGE &amp;lt;&lt;span class="o"&gt;=&lt;/span&gt; MAX_PAGES &lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"Fetching page &lt;/span&gt;&lt;span class="nv"&gt;$PAGE&lt;/span&gt;&lt;span class="s2"&gt; for &lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_YEAR_MONTH&lt;/span&gt;&lt;span class="s2"&gt; ... "&lt;/span&gt;
  &lt;span class="nv"&gt;RAW_JSON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$API_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"dateCreated=&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_YEAR_MONTH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"workPlace=remote"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"title=Java"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"language=en"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"page=&lt;/span&gt;&lt;span class="nv"&gt;$PAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-c&lt;/span&gt; .&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nv"&gt;TOTAL_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW_JSON&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.totalCount // 0'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;MAX_PAGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;TOTAL_COUNT &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt; &lt;span class="c"&gt;# calculate max pages and round up&lt;/span&gt;
  &lt;span class="o"&gt;((&lt;/span&gt;MAX_PAGES &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$REQUEST_LIMIT&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;MAX_PAGES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REQUEST_LIMIT&lt;/span&gt;
  &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"found &lt;/span&gt;&lt;span class="nv"&gt;$TOTAL_COUNT&lt;/span&gt;&lt;span class="s2"&gt; jobs resulting in &lt;/span&gt;&lt;span class="nv"&gt;$MAX_PAGES&lt;/span&gt;&lt;span class="s2"&gt; max pages we load for free&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="nv"&gt;JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW_JSON&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'.result'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  Error processing JSON on page &lt;/span&gt;&lt;span class="nv"&gt;$PAGE&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  ALL_JOBS+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$JOBS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;((&lt;/span&gt;PAGE++&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Combine all job postings into a single JSON array&lt;/span&gt;
&lt;span class="nv"&gt;COMBINED_JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ALL_JOBS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'add'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Save the combined job postings to a file&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMBINED_JOBS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; jobs.json

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Job postings fetched and saved to jobs.json"&lt;/span&gt;

&lt;span class="c"&gt;# Extract job data, create HTML table and send email&lt;/span&gt;
&lt;span class="nv"&gt;HTML_TABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'to_entries
  | map("    &amp;lt;tr&amp;gt; &amp;lt;td&amp;gt;\(.value.dateCreated | split("T") | .[0])&amp;lt;/td&amp;gt; &amp;lt;td&amp;gt;\(.value.title)&amp;lt;/td&amp;gt; &amp;lt;td&amp;gt;\(.value.company)&amp;lt;/td&amp;gt; &amp;lt;td&amp;gt;\(.value.jsonLD.url)&amp;lt;/td&amp;gt; &amp;lt;/tr&amp;gt;")
  | join("\n")
'&lt;/span&gt; jobs.json&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;HTML_TABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;table border='1'&amp;gt;
    &amp;lt;tr&amp;gt; &amp;lt;th&amp;gt;Date Posted&amp;lt;/th&amp;gt; &amp;lt;th&amp;gt;Title&amp;lt;/th&amp;gt; &amp;lt;th&amp;gt;Company&amp;lt;/th&amp;gt; &amp;lt;th&amp;gt;URL&amp;lt;/th&amp;gt; &amp;lt;/tr&amp;gt;
&lt;/span&gt;&lt;span class="nv"&gt;$HTML_TABLE&lt;/span&gt;&lt;span class="s2"&gt;
&amp;lt;/table&amp;gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"Subject: New Remote Job Postings&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Content-Type: text/html&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="nv"&gt;$HTML_TABLE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | sendmail &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EMAIL_RECIPIENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Job postings send to &lt;/span&gt;&lt;span class="nv"&gt;$EMAIL_RECIPIENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automating the Script with Cron
&lt;/h2&gt;

&lt;p&gt;To fully automate our job-fetching script, we can leverage Cron - the built-in scheduler in Unix-based systems like Linux and macOS - to run the script on a regular basis without manual intervention. Cron enables us to schedule commands or scripts to execute at specified intervals, ensuring that our remote job postings are fetched automatically. By simply adding an entry to the crontab, we can have the script run monthly on the 25th day, so we always receive the latest remote job postings.&lt;/p&gt;

&lt;p&gt;Before setting up the cron job, ensure that key parameters in the script are configured, such as &lt;code&gt;REQUEST_LIMIT&lt;/code&gt; (e.g., 25 if run monthly or 1 if run every workday) and your &lt;code&gt;RAPIDAPI_KEY&lt;/code&gt;. To schedule the script, open your crontab editor by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, append the following line to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 0 25 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /path/to/your/fetch_jobs.sh &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /tmp/fetch_jobs.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line instructs Cron to run the script at midnight on the 25th of every month, with all output (including errors) directed to &lt;code&gt;fetch_jobs.log&lt;/code&gt; for easy debugging. Finally, ensure that the script has execute permissions by running &lt;code&gt;chmod +x fetch_jobs.sh&lt;/code&gt;. With this setup in place, our personalized job alert system will automatically fetch and deliver fresh remote job postings each month, allowing you to potentially quit your old and apply to the new job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By completing this tutorial, we’ve not only automated a job search but also gained valuable skills in Bash scripting, API integration, and task automation. This project is a testament to how a little bit of coding can make a big difference in your daily life.&lt;/p&gt;

&lt;p&gt;To take it a step further, try customizing the script to suit your specific needs - whether that’s adding more precise filters, tweaking the email format, or scheduling it to run more frequently. If you encounter any issues, refer to the API documentation for more advanced features. Don’t forget to share your success with others or contribute to the project by improving the script. Happy automating!&lt;/p&gt;

</description>
      <category>sideprojects</category>
      <category>career</category>
      <category>api</category>
      <category>bash</category>
    </item>
    <item>
      <title>Weekend Project: Create a Personalized Job Posting Agent</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Sat, 14 Dec 2024 09:46:57 +0000</pubDate>
      <link>https://dev.to/joerg_rech/weekend-project-create-a-personalized-job-posting-agent-2p5a</link>
      <guid>https://dev.to/joerg_rech/weekend-project-create-a-personalized-job-posting-agent-2p5a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Job hunting can feel like a full-time job in itself. Tailoring searches and scanning multiple job boards every day can be time-consuming and overwhelming. A personalized job posting agent automates this process, saving you valuable time and effort—it’s like having your own digital assistant scouring the web for jobs that fit you.&lt;/p&gt;

&lt;p&gt;This tutorial helps you build a personalized job posting agent that queries job postings you're interested in from an API, formats the data, and emails it to you automatically. Whether you’re actively looking for a new role or just want to keep an eye on the market, this project is a practical and fun way to make technology work for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into the implementation, it’s crucial to prepare your system and set up the tools and services required for this tutorial. This setup will enable you to run the Python script, configure the cron job, and send email notifications.&lt;/p&gt;

&lt;p&gt;First, you need to create an account on &lt;a href="https://rapidapi.com/" rel="noopener noreferrer"&gt;RapidAPI&lt;/a&gt;, a platform that provides access to numerous APIs, including the job postings API we’ll use. Once your account is set up, go to the &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings" rel="noopener noreferrer"&gt;Daily International Job Postings API&lt;/a&gt;, subscribe to the free Basic plan, and obtain your API key. The Basic plan gives you access to 25 free requests with 10 job postings each per month.&lt;/p&gt;

&lt;p&gt;Second, you’ll need access to an &lt;strong&gt;SMTP&lt;/strong&gt;-based email provider, like Gmail. SMTP (Simple Mail Transfer Protocol) is the standard protocol for sending emails, and it allows your Python script to communicate with the email server to deliver messages. You'll need the SMTP server address and your credentials to send emails. Alternatively, you can start with printing the job postings into a file and create an calendar reminder to look at it.&lt;/p&gt;

&lt;p&gt;Next, install the necessary &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;Python&lt;/a&gt; tools and libraries for your operating system. You can use pip to install essential packages, including requests for making API calls, smtplib for sending emails, and any other dependencies specified in the code. Once all prerequisites are met, verify that your Python environment is functional by running &lt;code&gt;python3 --version&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: Using programming languages other than Python isn't too hard - RapidAPI shows the core API access for other languages in their &lt;code&gt;Code Snippets&lt;/code&gt; selector tab.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, on Linux or macOS, ensure that &lt;strong&gt;cron&lt;/strong&gt; is installed and operational; Windows users can achieve similar functionality using &lt;strong&gt;Task Scheduler&lt;/strong&gt;. These tools will enable the automation of your Python script at specified intervals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Job Postings API
&lt;/h2&gt;

&lt;p&gt;Techmap's &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings" rel="noopener noreferrer"&gt;Daily International Job Postings API&lt;/a&gt; provides comprehensive access to global job data from the last 3 months. It returns structured job postings and supports queries with various filtering parameters to narrow search results such as date of posting, location, occupation, and required skills.&lt;/p&gt;

&lt;p&gt;You can find the documentation for constructing API requests on &lt;a href="https://rapidapi.com/techmap-io-techmap-io-default/api/daily-international-job-postings/playground/apiendpoint_364eb770-3659-4905-9f9f-511a36c41218" rel="noopener noreferrer"&gt;RapidAPI's  Playground for the Paginated Search&lt;/a&gt; or the &lt;a href="https://api.techmap.io" rel="noopener noreferrer"&gt;API's OpenAPI documentation page&lt;/a&gt;. We will use the &lt;code&gt;/api/v2/jobs/search&lt;/code&gt; endpoint with the following query parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dateCreated&lt;/code&gt; for filtering jobs posted on a specific date (day or month),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;countryCode&lt;/code&gt; for selecting the country (using the ISO3166 codes),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;city&lt;/code&gt; for specifying a particular city,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;occupation&lt;/code&gt; for job type, (using many synonyms)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills&lt;/code&gt; for required expertise, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;page&lt;/code&gt; to paginate through larger lists of jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These parameters help us in building a personalized job posting agent for a specific type of occupation in a specific area. The API returns data in &lt;a href="https://schema.org" rel="noopener noreferrer"&gt;Schema.org Microdata&lt;/a&gt; format using JSON, which is ideal for parsing, further processing, or direct use in webpages to improve SEO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a Query with Parameters
&lt;/h3&gt;

&lt;p&gt;To query job postings in Python using the API, you need to structure your request with the appropriate parameters. Consider the following example parameter configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parameters = {
  "dateCreated": "2024-12",    # Filter jobs posted for December 2024
  "countryCode": "de",         # Country code for Germany
  "city":        "Berlin",     # Specific city in Germany
  "occupation":  "Programmer", # Job type
  "skills":      "Java"        # Required skill
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These parameters allow you to filter job postings precisely for a programmer role in Berlin, Germany, looking for expertise in Java. If more than 10 results are found we'll be adding the pagination (page) parameter to fetch additional results.&lt;/p&gt;

&lt;p&gt;These parameters will be used to construct the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2024&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Berlin&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;occupation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Programmer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Java&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can use other parameters described in the API documentation such as &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;workPlace&lt;/code&gt; (e.g. remote or hybrid), &lt;code&gt;company&lt;/code&gt;, geoPoints, timezones, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Remote jobs in core US Timezones (UTC-8 to UTC-5):&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;workPlace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;remote&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;timezoneMin&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;timezoneMax&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;

&lt;span class="c1"&gt;// Jobs in the Healthcare industry of the United Kingdom:&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;uk&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;industry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;healthcare&lt;/span&gt;

&lt;span class="c1"&gt;// Jobs for Java Developers in San Francisco:&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Java&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;occupation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;java&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;programmer&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;geoPointLat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;37.757&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;geoPointLng&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mf"&gt;122.449&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;geoDistance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;mi&lt;/span&gt;

&lt;span class="c1"&gt;// Jobs for JavaScript Developers in New York, USA:&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;skills&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;JavaScript&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;us&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;York&lt;/span&gt;

&lt;span class="c1"&gt;// Jobs in English language located in Germany:&lt;/span&gt;
&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;dateCreated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;countryCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;en&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NOTE: Please remember that the free Basic Account only gives 25 free requests per month - it's probably best to start with our example parameters and then tailor it to you needs. Nevertheless, the API is cheap and 100 requests over the free ones only cost 5$.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using curl to Call the API
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;curl&lt;/code&gt; command is an easy way to interact with the API via the terminal and test different queries and parameters. Here’s how you can query the API using curl with the above parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search?dateCreated=2024-12&amp;amp;countryCode=de&amp;amp;city=Berlin&amp;amp;occupation=Programmer&amp;amp;skills=Java&amp;amp;page=1'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: daily-international-job-postings.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: &amp;lt;YOUR_API_KEY&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After replacing &lt;code&gt;&amp;lt;YOUR_API_KEY&amp;gt;&lt;/code&gt; with your unique API key obtained from RapidAPI, this command sends a GET request to the API endpoint, including the query parameters and authentication headers. The response, in JSON format, will contain the job postings matching your criteria including a description of the query that the server understood.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calling the API with Python
&lt;/h3&gt;

&lt;p&gt;Using Python to call the API offers greater flexibility for processing and integrating the data into your application. Here’s an example code snippet that achieves this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="c1"&gt;# API endpoint and headers
&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;daily-international-job-postings.p.rapidapi.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_API_KEY&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Query parameters
&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dateCreated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2024-12&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;countryCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Berlin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;occupation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Programmer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skills&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Make the GET request
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Check for successful response
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;job_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Parse JSON response
&lt;/span&gt;  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;totalCount&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; jobs.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script constructs the request, sends it to the API, and processes the JSON response to extract job postings. By using Python, you can further manipulate and analyze the data, save it to a file, store it in a database, or send notifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The complete picture
&lt;/h2&gt;

&lt;p&gt;After we covered the basics, we will walk through the full implementation of the personalized job posting agent python script. This script fetches job postings from an API based on specified parameters, processes the data to ensure relevance, and sends a customized email notification to the user. The main parts of the script are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Importing Required Libraries&lt;/strong&gt;: The script begins by importing the necessary Python libraries for handling API requests, email communication, file manipulation, and data processing. These libraries provide the core functionality required to fetch, process, and email job postings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting Up Variables and Configuration&lt;/strong&gt;: To personalize the job search, the script defines variables for the API query parameters, email configuration, and file paths. These variables can be easily adjusted to suit the user’s requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fetching Job Postings with Pagination&lt;/strong&gt;: The script queries the API in a loop to handle pagination, ensuring all relevant job postings are fetched. Results are written to a temporary file for further processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deduplicate and sort Database File&lt;/strong&gt;: After fetching the job postings, the script processes the data to remove duplicates and sorts the entries by the dateCreated field in descending order. The cleaned data is saved to a final JSON file for record-keeping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sending the Email&lt;/strong&gt;: Finally, the script sends an email containing the job postings to the specified recipient. The email content is read from the prepared file, and the SMTP library is used to send the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To sum it up, the main script for the personalized job posting agent in detail looks as follows, combining all the steps above. The script is modular and can be customized easily by changing the query parameters or email configurations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: to run this script you need to edit the configuration and replace the placeholders for EMAIL_TO, SMTP_* info, API_KEY,  city, occupation, and skills.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  File: fetch_jobs_and_email.sh
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;################################
# Importing Required Libraries #
################################
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;smtplib&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;email.mime.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MIMEText&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sleep&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;operator&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;itemgetter&lt;/span&gt;

&lt;span class="c1"&gt;##########################################
# Setting Up Variables and Configuration #
##########################################
&lt;/span&gt;
&lt;span class="c1"&gt;# Current date in "yyyy-MM" format - "yyyy-MM-dd" is possible
&lt;/span&gt;&lt;span class="n"&gt;DATE_CREATED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Email Configuration
&lt;/span&gt;&lt;span class="n"&gt;EMAIL_TO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recipient@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SMTP_SERVER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smtp.gmail.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SMTP_FROM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;SMTP_FROM_ACCOUNT_EMAIL&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SMTP_PASS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;SMTP_PASSWORD&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_SUBJECT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My Daily Job Postings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;EMAIL_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;techmap_jobs_email.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Prepare the email file
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMAIL_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;email_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;email_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Job Postings in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DATE_CREATED&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; for you:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;email_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;======================================&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;JOB_FILE_TEMP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;techmap_jobs_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DATE_CREATED&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_all.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;JOB_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;techmap_jobs_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DATE_CREATED&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# API details
&lt;/span&gt;&lt;span class="n"&gt;MAX_REQUESTS_PER_MONTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;
&lt;span class="n"&gt;MAX_REQUESTS_PER_CALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# use 2 for tests and 5 for weekly execution
&lt;/span&gt;&lt;span class="n"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;API_HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;daily-international-job-postings.p.rapidapi.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR_API_KEY&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Query parameters
&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dateCreated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DATE_CREATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;countryCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Berlin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;occupation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Programmer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skills&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#########################################
# Fetching Job Postings with Pagination #
#########################################
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fetching job postings for date: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DATE_CREATED&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;PAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;TOTAL_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MAX_REQUESTS_PER_CALL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Add pagination to parameters
&lt;/span&gt;  &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PAGE&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Querying: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_ENDPOINT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; with parameters &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;API_ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_KEY&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: Failed to fetch jobs (Maybe the API_KEY): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;

  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;TOTAL_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;totalCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;page_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pageSize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; jobs of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TOTAL_COUNT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; on page: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PAGE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No more jobs found. Stopping.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;

  &lt;span class="c1"&gt;# Save jobs to temporary file
&lt;/span&gt;  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JOB_FILE_TEMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;temp_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;temp_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Write email content to Database File
&lt;/span&gt;  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMAIL_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;email_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dateCreated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="n"&gt;email_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Company: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;City: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Posted On: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dateCreated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;URL: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jsonLD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Stop if there are no more results
&lt;/span&gt;  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;page_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;

  &lt;span class="n"&gt;PAGE&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;PAGE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_REQUESTS_PER_CALL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Max requests reached. Exiting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="c1"&gt;# Sleep due to throttled access to API
&lt;/span&gt;  &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;######################################
# Deduplicate and sort Database File #
######################################
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JOB_FILE_TEMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;temp_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;job_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;temp_file&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# Deduplicate
&lt;/span&gt;  &lt;span class="n"&gt;deduplicated_jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sort_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;job_list&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;# Sort by dateCreated in reverse order
&lt;/span&gt;  &lt;span class="n"&gt;sorted_jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deduplicated_jobs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;itemgetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dateCreated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Save the sorted, deduplicated results to the final job file
&lt;/span&gt;  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JOB_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;final_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sorted_jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;final_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Successfully deduplicated and sorted: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JOB_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: Error processing job files: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#####################
# Sending the Email #
#####################
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending email to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;EMAIL_TO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMAIL_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;email_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MIMEText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EMAIL_SUBJECT&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;From&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SMTP_FROM&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;To&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EMAIL_TO&lt;/span&gt;
  &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;smtplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SMTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SMTP_SERVER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;starttls&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SMTP_FROM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SMTP_PASS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Update with your credentials
&lt;/span&gt;    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email sent successfully.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: Failed to send email (maybe wrong SMTP info): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Done fetching job postings.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up a Weekly Schedule
&lt;/h2&gt;

&lt;p&gt;To automate the Python script to run on a weekly schedule, you’ll need to configure a task scheduler specific to your operating system. Here’s how to do it on MacOS, Windows, and Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Cron Jobs on MacOS or Linux
&lt;/h3&gt;

&lt;p&gt;On MacOS and Linux, you can use &lt;code&gt;cron&lt;/code&gt;, a built-in task scheduler, to automate your script. Follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open the Terminal&lt;/strong&gt;: On MacOS press Command + Space to open the Spotlight search bar, type Terminal, and hit Enter. On Linux start a shell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit the Crontab&lt;/strong&gt;: Type &lt;code&gt;crontab -e&lt;/code&gt; to open the cron configuration file. If prompted, choose a text editor such as nano or vim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add the Cron Job&lt;/strong&gt;: To schedule the Python script to run weekly, add the line below. This runs the script every Saturday at 6:00 AM. Replace &lt;code&gt;/usr/local/bin/python3&lt;/code&gt; with the path to your Python interpreter and &lt;code&gt;/path/to/your_script.py&lt;/code&gt; with the full path to your Python script.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 6 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 6 /usr/local/bin/python3 /path/to/your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Save and Exit&lt;/strong&gt;: Save the file (Ctrl + O in nano; Esc and ':x!' in vim) and exit (Ctrl + X in nano).&lt;/li&gt;
&lt;li&gt;Finally, you can check if the cron job is active with &lt;code&gt;crontab -l&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting up the Cron Jobs on Windows
&lt;/h3&gt;

&lt;p&gt;Windows uses the Task Scheduler for automation. Here’s how to set up a weekly task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Task Scheduler&lt;/strong&gt;: Search for &lt;code&gt;Task Scheduler&lt;/code&gt; in the Start menu and open it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a New Task&lt;/strong&gt;: Click on &lt;code&gt;Create Basic Task&lt;/code&gt; in the right-hand menu, name your task (e.g., “Weekly Job Agent Python Script”) and click &lt;code&gt;Next&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set the Schedule&lt;/strong&gt;: Choose &lt;code&gt;Weekly&lt;/code&gt; and specify the day of the week and time you want the script to run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure the Action&lt;/strong&gt;: Choose &lt;code&gt;Start a Program.&lt;/code&gt;, and enter the path to your Python executable (e.g., &lt;code&gt;C:\Python39\python.exe&lt;/code&gt;) in the Program/Script field. In the Add Arguments field, enter the full path to your script (e.g., &lt;code&gt;C:\path\to\your_script.py&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finish the Setup&lt;/strong&gt;: Confirm and save the task. Your script will now run automatically as scheduled.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we developed a fully functional and personalized job posting agent in Python to automate the retrieval of job postings using an API, customized the results for specific criteria, and sent the data as a formatted email notification. The script demonstrates how to query different API parameters such as location, occupation, and skills. With just a few adjustments, you can fetch data tailored to a wide range of use cases, from remote jobs in specific time zones to opportunities in specific industries or geographic regions.&lt;/p&gt;

&lt;p&gt;Beyond sending notifications, the collected job data opens doors to more advanced applications. For instance, storing the retrieved job postings in a database enables the creation of a niche job board. You could enhance this board by integrating search and filtering features, allowing users to find tailored job opportunities. Additionally, analyzing this data for trends—such as demand for specific skills, regional salary variations, or emerging industries—could provide valuable insights for businesses and job seekers alike.&lt;/p&gt;

&lt;p&gt;I hope you found value in this tutorial and are inspired to try it out as a personal project over a weekend or holidays. It’s an excellent opportunity to enhance your Python skills, experiment with API integration, and explore the world of automation.&lt;/p&gt;

</description>
      <category>career</category>
      <category>sideprojects</category>
      <category>weekend</category>
      <category>programming</category>
    </item>
    <item>
      <title>How you can extract company signals from job postings</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Thu, 25 Jul 2024 13:59:37 +0000</pubDate>
      <link>https://dev.to/joerg_rech/how-you-can-extract-company-signals-from-job-postings-431o</link>
      <guid>https://dev.to/joerg_rech/how-you-can-extract-company-signals-from-job-postings-431o</guid>
      <description>&lt;h2&gt;
  
  
  Identifying New Office Locations in Job Postings
&lt;/h2&gt;

&lt;p&gt;As software developers, we know the importance of staying ahead in the tech industry, whether it's through learning new programming languages or understanding market trends. By analyzing job postings from companies, we can uncover new office locations, reveal growing tech hubs, or even identifying potential business partners for freelancing.&lt;/p&gt;

&lt;p&gt;Imagine knowing that a major tech company is setting up a new office before everyone else does—that's the kind of edge we’re talking about. Let's dive into how we can do this using practical steps and tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basics: Job Postings and Company Signals
&lt;/h2&gt;

&lt;p&gt;Job postings are typically targeted at potential new employees and used to create awareness that a company exists, is hiring for a specific role, why they are hiring, what skills an applicant should have, what the company works on, and provide insights into what companies does, plan, want, use, build, etc.&lt;/p&gt;

&lt;p&gt;But job posting also contain many signals what a company is up to and are indicators that provide insights into a company's activities, strategies, and future plans. They help to identify sales opportunities, understand market trends, and develop targeted sales strategies. These signals can be derived from various sources, including job postings, press releases, financial reports, social media activity, and more.&lt;/p&gt;

&lt;p&gt;In the remaining of this post we will use the &lt;a href="https://aws.amazon.com/marketplace/pp/prodview-p2554p3tczbes" rel="noopener noreferrer"&gt;free Luxembourg job posting data feed from Techmap on AWS Data Exchange (ADX)&lt;/a&gt; which gives access to all our historical data since January 2020. More specifically, we use the data from June 2024 with 14.7k job postings where the main sources are Linkedin, CareerJet, Indeed, Eures, and Smartrecruiters. For Luxembourg the compressed data files, typically, have a size between 100KB and 1.5MB per day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying New Office Locations in Job Postings
&lt;/h2&gt;

&lt;p&gt;As Luxembourg has multiple official languages, we can identify location signals in English, French, and German. Furthermore, the regular expressions can identify location signals by using synonyms used by the hiring companies, such as “bureau” or “premise” instead of “office”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(?i)\b(
  (new (\w+ ){0,2}(office|premise|location|facilit(y|ie)|site)s?)
  |(nouveau (\w+ ){0,2}(bureau|locaux|facilité|site)s?)
  |(neue(n|m|s)? (\w+ ){0,2}(Büro|Office|Räum(en|lichkeiten)|Standorte?|Einrichtung(en)?))
  |(we (are )?(expand(ing)?) to)|(nous (\w+ )?(étendons|développons?) (à|en))
  |(wir (\w+ )?(expandieren) nach)
)\b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extracting Location Signals from Job Postings
&lt;/h2&gt;

&lt;p&gt;In order to use the job postings you can follow &lt;a href="https://docs.aws.amazon.com/data-exchange/latest/userguide/subscriber-tutorial-s3-product.html" rel="noopener noreferrer"&gt;AWS’s tutorial to subscribe to AWS Data Exchange for Amazon S3&lt;/a&gt; but use our &lt;a href="https://aws.amazon.com/marketplace/pp/prodview-p2554p3tczbes" rel="noopener noreferrer"&gt;free Luxembourg data feed on ADX&lt;/a&gt; instead of their test product.&lt;/p&gt;

&lt;p&gt;Then you can download the files from AWS ADX and decompress all files from June 2024 (results in 130 MB)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 sync \
    s3://&amp;lt;YOUR_BUCKET_ALIAS&amp;gt;/lu/ . \
    --request-payer requester \
    --exclude "*" \
    --include "techmap_jobs_lu_2024-06-*.jsonl.gz"

gzip -d *.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have the job postings in textual files with JSON Lines format, we can program the identification of location signals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define the regex as an environment variable &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REGEX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\b((new (\w+ ){0,2}(office|premise|location|facilit(y|ie)|site)s?)|(nouveau (\w+ ){0,2}(bureau|locaux|facilité|site)s?)|(neue(n|m|s)? (\w+ ){0,2}(Büro|Office|Räum(en|lichkeiten)|Standorte?|Einrichtung(en)?))|(we (are )?(expand(ing)?) to)|(nous (\w+ )?(étendons|développons?) (à|en))|(wir (\w+ )?(expandieren) nach))\b'&lt;/span&gt; 

&lt;span class="c"&gt;# Define and clear output file for the results &lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"location_signals.txt"&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Loop over all files matching the pattern&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;file &lt;span class="k"&gt;in &lt;/span&gt;techmap_jobs_lu_2024-06-&lt;span class="k"&gt;*&lt;/span&gt;.jsonl&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# Check if the file exists to avoid errors if no files match the pattern&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Decompress the file, filter JSON lines with jq, and extract fields&lt;/span&gt;
        &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; regex &lt;span class="s2"&gt;".{0,20}&lt;/span&gt;&lt;span class="nv"&gt;$REGEX&lt;/span&gt;&lt;span class="s2"&gt;.{0,20}"&lt;/span&gt; &lt;span class="s1"&gt;'
            select(
                . | to_entries[] | select(.value | type == "string" and test($regex))
            ) | {
                job_name: .name,
                job_url: .url,
                company_name: .company.name,
                location: (.location.orgAddress.addressLine // .location.orgAddress.city),
                matched_text: [
                    . | to_entries[] | select(.value | type == "string" and test($regex)) | .value | match($regex).string
                ] | unique | map("..." + . + "...") | join(", ")
            }
        '&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No files matching the pattern found."&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To extract unique companies from job postings, regardless of the number of postings they placed, use the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;location_signals.txt | &lt;span class="nb"&gt;grep &lt;/span&gt;company_name | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And get a result that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allianz Global Investors"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amazon EU Sarl - A84"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amazon EU Sarl"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amazon"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ArcelorMittal"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Astel Medica"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Deloitte"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Euro Exim Bank"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Koch Global Services"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Koch Industries"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Luxscan Weinig Group"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MD Skin Solutions"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROTAREX"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Thales"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e-Consulting RH, Sourcing &amp;amp; Recrutement de Profils pénuriques"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myGwork - LGBTQ+ Business Community"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, in under a minute, we identified 144 job postings in Luxembourg mentioning new offices in June 2024. After refining the data, we pinpointed 16 unique companies with location signals, showcasing the effectiveness of our extraction method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we showed how to identify 144 job postings mentioning a location change for 16 unique companies in June 2024 in Luxembourg. A similar analysis in the USA revealed 1241 signals from 918k job postings (i.e., ~1 signal per 1k job postings).&lt;/p&gt;

&lt;p&gt;For more details, check out our full article on &lt;a href="https://jobdatafeeds.com/blog/post/how-to-identify-new-office-locations-in-job-postings" rel="noopener noreferrer"&gt;how to extract company signals from job postings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested in further exploring the potential of job postings or applying machine learning / AI techniques, we encourage you to experiment with our data feed and source code provided in this article. Happy analyzing!&lt;/p&gt;

</description>
      <category>companysignals</category>
      <category>jobpostings</category>
      <category>datascience</category>
      <category>career</category>
    </item>
    <item>
      <title>Harness the Power of Job Ads to Boost Your Ad Revenue</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Tue, 12 Sep 2023 13:08:20 +0000</pubDate>
      <link>https://dev.to/techmap/harness-the-power-of-job-ads-to-boost-your-ad-revenue-54d</link>
      <guid>https://dev.to/techmap/harness-the-power-of-job-ads-to-boost-your-ad-revenue-54d</guid>
      <description>&lt;p&gt;Are you looking for a way to increase your ad revenue and gain valuable insights into the job market? Look no further than job ads datasets! With access to comprehensive data on job postings, you can uncover emerging trends, identify new markets, and stay informed about your competitors. In this article, we will explore how harnessing the power of job ads can help you boost your ad revenue and drive your business growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Job Ads Datasets Matter
&lt;/h2&gt;

&lt;p&gt;Job postings provide a wealth of information that can be leveraged to enhance your business intelligence capabilities. By analyzing job ads datasets, you can gain insights into hiring trends within specific industries or regions. This information is invaluable for market research, competitor analysis, and identifying potential sales leads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uncover Emerging Trends
&lt;/h3&gt;

&lt;p&gt;One of the key benefits of analyzing job ads datasets is the ability to identify emerging trends in job roles, technologies, and markets. By monitoring job postings in a particular industry or region, you can spot new and upcoming job titles or skills that are in high demand. This information can help you align your products or services with market needs and stay ahead of the competition.&lt;/p&gt;

&lt;p&gt;For example, let's say you run an online learning platform that offers courses on data science. By analyzing job ads datasets, you may discover a surge in demand for professionals with expertise in machine learning or natural language processing. Armed with this knowledge, you can develop new courses or update existing ones to cater to this growing market.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stay Informed About Competitors
&lt;/h3&gt;

&lt;p&gt;Job ads datasets can also provide valuable insights into your competitors' hiring strategies and growth trajectory. By monitoring the job postings of competing companies, you can gain a better understanding of their organizational structure, focus on specific departments, or expansion into new locations.&lt;/p&gt;

&lt;p&gt;For instance, if you are a headhunter looking to place candidates in high-growth companies, analyzing job ads datasets can help you identify companies that are actively hiring. This information allows you to target your efforts towards organizations that are in need of employees and increase your chances of successful placements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimize Your Hiring Strategy
&lt;/h3&gt;

&lt;p&gt;Analyzing job ads datasets can also provide valuable insights into labor market trends and help optimize your own hiring strategy. By understanding changes in candidate preferences, skill requirements, or benefits offered by employers, you can tailor your recruitment efforts to attract top talent.&lt;/p&gt;

&lt;p&gt;Let's say you are a recruiter for a tech company specializing in artificial intelligence. By analyzing job ads datasets, you may notice a shift in the desired skills for AI roles, such as an increased emphasis on deep learning or experience with specific programming languages. Armed with this knowledge, you can adjust your job descriptions and screening criteria to attract candidates who possess these sought-after skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Job Ads Datasets Drive Ad Revenue
&lt;/h2&gt;

&lt;p&gt;Now that we understand the value of job ads datasets, let's explore how they can specifically boost your ad revenue. By leveraging job postings, you can enhance your sales intelligence capabilities and uncover new leads for companies that may be interested in your solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identify Companies in Need of Employees
&lt;/h3&gt;

&lt;p&gt;As a headhunter or recruitment agency, job ads datasets can be a goldmine for identifying companies in need of employees. By analyzing job postings from various industries and regions, you can compile a list of organizations actively hiring for specific roles.&lt;/p&gt;

&lt;p&gt;With this information at hand, you can reach out to these companies and offer your services as a headhunter. This targeted approach increases your chances of success and allows you to place your candidates more efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promote Your Courses or Services
&lt;/h3&gt;

&lt;p&gt;If you are an educator offering courses or training programs, job ads datasets can help you promote your offerings to individuals seeking to acquire new skills or advance their careers. By analyzing the skills and qualifications required by employers in job postings, you can identify gaps in the market where your courses or services can provide value.&lt;/p&gt;

&lt;p&gt;For example, if there is a high demand for professionals with expertise in cloud computing, you can develop and market courses that cater to this specific skill set. By aligning your offerings with market needs, you increase the likelihood of attracting students who are actively seeking to acquire those skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offer Your Tools or Software
&lt;/h3&gt;

&lt;p&gt;If you are a software manufacturer or provider of tools and solutions, job ads datasets can help you identify potential customers who may benefit from your products. By analyzing job postings, you can gain insights into the tools and technologies used by companies in specific industries.&lt;/p&gt;

&lt;p&gt;For instance, if you manufacture a data analytics platform, analyzing job ads datasets may reveal a growing demand for professionals with experience in big data processing. Armed with this knowledge, you can target your marketing efforts towards organizations that are actively seeking to hire individuals with these skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Power of Job Ads Datasets
&lt;/h2&gt;

&lt;p&gt;In conclusion, harnessing the power of job ads datasets can significantly boost your ad revenue and provide valuable insights into the job market. Whether you are conducting market research, optimizing your hiring strategy, or promoting your products or services, job ads datasets offer unparalleled opportunities for growth and success.&lt;/p&gt;

&lt;p&gt;Operating your own scraping infrastructure to collect job posting data can be time-consuming and costly. Instead, consider leveraging pre-existing job posting datafeeds like Techmap's. With flexible pricing options and support for various data formats, Techmap's job posting datafeeds provide easy access to comprehensive datasets that can fuel your business intelligence activities.&lt;/p&gt;

&lt;p&gt;Don't miss out on the opportunity to enhance your data science capabilities, uncover emerging trends, and gain valuable insights into hiring practices. Contact Techmap today to learn more about their job posting datasets and how they can help drive your growth and success.&lt;/p&gt;

</description>
      <category>datascience</category>
    </item>
    <item>
      <title>How Job Ads Data Uncovers Market Trends</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Mon, 03 Jul 2023 15:33:06 +0000</pubDate>
      <link>https://dev.to/joerg_rech/how-job-ads-data-uncovers-market-trends-4l70</link>
      <guid>https://dev.to/joerg_rech/how-job-ads-data-uncovers-market-trends-4l70</guid>
      <description>&lt;p&gt;Discover how analyzing job ads data can provide valuable insights into market trends, helping businesses in commercial investigation and trend identification.&lt;/p&gt;

&lt;p&gt;More at: &lt;a href="https://jobdatafeeds.com/blog/post/how-job-ads-data-uncovers-market-trends"&gt;https://jobdatafeeds.com/blog/post/how-job-ads-data-uncovers-market-trends&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dataanalysis</category>
    </item>
    <item>
      <title>Master the Art of Competitive Intelligence with Job Posting Data</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Sun, 02 Jul 2023 10:58:43 +0000</pubDate>
      <link>https://dev.to/joerg_rech/master-the-art-of-competitive-intelligence-with-job-posting-data-3lde</link>
      <guid>https://dev.to/joerg_rech/master-the-art-of-competitive-intelligence-with-job-posting-data-3lde</guid>
      <description>&lt;p&gt;Unlock valuable market insights and stay ahead of the competition by leveraging job posting data. Discover emerging trends, analyze hiring practices, and enhance your competitive intelligence capabilities.&lt;/p&gt;

&lt;p&gt;More at: &lt;a href="https://jobdatafeeds.com/blog/post/master-the-art-of-competitive-intelligence-with-job-posting-data"&gt;https://jobdatafeeds.com/blog/post/master-the-art-of-competitive-intelligence-with-job-posting-data&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
    </item>
    <item>
      <title>Improving Candidate Experience with Job Posting Data</title>
      <dc:creator>Joerg Rech</dc:creator>
      <pubDate>Sat, 01 Jul 2023 09:09:54 +0000</pubDate>
      <link>https://dev.to/techmap/improving-candidate-experience-with-job-posting-data-4g8k</link>
      <guid>https://dev.to/techmap/improving-candidate-experience-with-job-posting-data-4g8k</guid>
      <description>&lt;p&gt;Enhance candidate experience and optimize your recruitment strategy by leveraging job posting data. Gain insights into hiring trends and industry standards to make informed decisions. Learn how to use HR data and web scraping job ads effectively.&lt;/p&gt;

</description>
      <category>recruitmentstrategy</category>
    </item>
  </channel>
</rss>
