Automate Your Job Search with Twitter and Twilio Programmable SMS

October 22, 2020
Written by
Contributor
Opinions expressed by Twilio contributors are their own
Reviewed by
Twilion

job-search-twitter.png

Job search is a tedious and time-consuming task. Last year, when I was on a job hunt, I looked for opportunities everywhere - LinkedIn, Facebook groups, Slack channels, Twitter, Indeed, Glassdoor, and sometimes Instagram.

Given that there's a huge tech community on Twitter, I found it easier to look for jobs there. To reach out directly to the people who posted the job and get a response from them, positive or negative, made the job search less tiresome. There was no cold messaging, awkward introductions, or long wait as to whether a real person had read my resume or not.

I'd search on Twitter for keywords like looking for frontend and hiring frontend. I'd scroll through all the results and open the compelling opportunities in new tabs. And before I knew it, I had several tabs open for review.

Combing through Twitter became a daily practice, and then, one day, I realized I could automate this process. Instead of searching for tweets manually, I created a script that would search recent tweets for specific keywords and create a .csv file with all the information I need.

Prerequisites

The script saved me a lot of time and got me a few interviews. Let's walk through the script and see how you can customize it according to your needs. Throughout this article, you’ll use the following tools:

  1. Node.js installed on your machine
  2. Twitter access key
  3. Twilio credentials and a Twilio phone number 
  4. Objects-to-csv - This package converts objects into a CSV format
  5. Twit - Twit is a Twitter API Client for Node, making it easier to interact with Twitter API
  6. dotenv - You will use dotenv to load your access keys and tokens

Twitter

To make any request to the Twitter API, you must first have a developer account. For detailed instructions, you can read the Getting Started documentation.

Create your developer account here. Once you land on the page, Twitter will ask the reason behind accessing their API. There are a couple of options to choose from, but you will go with Exploring the API.

What is your primary reason for using Twitter developer tools?

On the next page, Twitter will ask a few questions to verify your identity. Once you have confirmed your identity, you will answer some questions about your intended use.

Verifying Identity

Click Next to submit. Follow the instructions on the next page, and then you’ll be asked to name your application. The name could be anything, but it should be unique.

And that's it. Once you give your application a name, you will be provided with your API key and API secret key.

On your dashboard, you should see your application under Projects & Apps. Select your application and go to the Keys and Token tab. You already have your API key and API secret key, but you still need your Access Token and Secret. Generate them; you will need these for your next step.

Tokens and Secrets

Installation and Code

Instead of directly accessing Twitter’s API, you will use Twit - an npm package to simplify your interactions.

First, create a project directory called AutomateJobSearch. Open your terminal and execute the following command:

mkdir AutomateJobSearch && cd AutomateJobSearch && touch app.js

Let’s break down what you just did:

  1. From your chosen parent directory, you used mkdir to create a new directory called AutomateJobSearch
  2. You changed your directory to the newly created folder
  3. You created a file called app.js 

Next, install twitobjects-to-csvdotenv, and twilio:

npm install twit objects-to-csv dotenv twilio

At the top of app.js, add the following code to add these packages to your project:

const Twit = require('twit'); 
const ObjectsToCsv = require('objects-to-csv');
require('dotenv').config()

You need to use your keys and tokens before Twit can access tweets:

  • For cosumer_key, you will use your API key
  • For consumer_secret, you will use your API secret key
  • For access_token and access_token_secret, you will use Access Token and Access Token Secret respectively.

For safety's sake, instead of adding these credentials directly to the new Twit instance, you will load them from a .env file.

Create a new file called .env in your project’s root directory and paste in the following text, replacing the placeholder values with your credentials as described above:

export API_KEY=yourAPIKey
export API_SECRET_KEY=YourAPISecretKey
export ACCESS_TOKEN=yourAccessToken
export ACCESS_TOKEN_SECRET=yourAccessTokenSecret 

Back in app.js, create a new Twit instance that will be used to make requests to Twitter's APIs. You will initialize this instance with an object containing your API key, API secret key, Access Token, and Access Token Secret.

var T = new Twit({
  consumer_key:    process.env.API_KEY,
  consumer_secret: process.env.API_SECRET_KEY,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret:  process.env.ACCESS_TOKEN_SECRET
});

There are many tasks you can do with Twit: search tweets, post tweets, delete tweets, get the list of user ID's that follow @twilio, among others.

In this case, you want to search for tweets containing specific words.

Here comes the essential non-technical part: your query parameter neither can be too detailed nor too general. If it is too broad, you will see useless tweets, and if it's too specific, you will see fewer tweets. We don't want either.

To get to a useful query parameter, you will attempt trial-and-error. When I was looking for a frontend job on Twitter, I noticed a pattern. Most of the tweets looking for a frontend developer used the words 'looking,' 'hiring', and 'frontend'. Some tweets used 'front end' instead of 'frontend.' When I am looking for writing opportunities, I search for 'call for pitches,' and 'looking for pitch.'  

Keep in mind that you have to have a balance, so you shouldn't worry about grammar. You might find fewer results if you search for 'looking for a frontend' instead of 'looking for frontend.' Another thing that has been helpful in my search is to use singular words instead of plural. Instead of searching for 'pitches,' try 'pitch.' This way, you will get both of them.

For this project, you will search for 'looking for frontend.' Add the following code to app.js beneath your Twit configuration:

 T.get('search/tweets', { q: 'looking for frontend', count: 1 }, async (err, data, response) => {
   console.log(data);
 })

If you want to search for tweets from a specific time, you can update your query parameter, i.e. {q: 'looking for frontend since:2020-09-01'}. The default search count is 15, but you can edit this value to a higher number.

Save your file and run your app to see what the search returns. In your terminal, from your project’s root directory, run the command node app.js.

Screenshot of Terminal with Twitter return Data

As you can see, the search returns an object which contains two properties: statuses and metadata. Since your count attribute was set to one, only one tweet was returned and you see only one object in your statuses array. Each object in the statuses array gives us information about one tweet. Metadata, on the other hand, gives us the data about the data.

For this project, you’ll be working with this statuses array. Every tweet is represented by an object with multiple properties. For your purposes, you only need a handful of these properties. These properties include created_at, text, user.name, id_string, and user.screen_name.

Let’s continue to edit the callback function in app.js.

First, you will save your statuses array in a variable called statuses. Then, you’ll loop through this array. For each tweet in the array, you will capture the data you need into a new object, and push this object into a new array called tweets. The keys of the new objects will be the column titles of your .csv file.


T.get('search/tweets', { q: 'looking for frontend', count: 100 }, async (err, data, response) => {
  const statuses = data.statuses;
  const tweets = [];

  statuses.map(status => {
    tweets.push({
      time: status.created_at,
      text: status.text,
      name: status.user.name,
      screen_name: status.user.screen_name,
      tweet_url: `https://twitter.com/${status.user.screen_name}/status/${status.id_str}`
    });
  });
});

Earlier, you installed an npm package called objects-to-csv. This package will help us convert your sanitized array of JavaScript objects into a .csv file. Right after your map function ends, you will add the highlighted lines:


T.get('search/tweets', { q: 'looking for frontend', count: 100 }, async (err, data, response) => {
  ...

  const csv = await new ObjectsToCsv(tweets)
  await csv.toDisk('./tweets.csv', { append: true })
});

When you create a new instance of ObjectsToCsv, you will initialize it with your new tweets array. And then, using the toDisk method, you will write your data to a .csv file. Make sure to set append to true otherwise, every time you run the program, it will overwrite any existing data in the file.

And that's it. After saving your file, if you run your program, using the command node app.js, you will see a .csv file called tweets.csv has been created in your folder.

Remind Me Daily, Twilio

I would manually run this program every night and comb through the tweets until I learned about cron jobs.

Instead of manually running your code every day, you can set up a cron job and let it automatically run the script for you. You can use Twilio's SMS service and send yourself a message when it's done for a daily reminder.

Get set up with Twilio Programmable SMS. First, create a free Twilio account.

twilio sign up page

Once you've created an account, Twilio will verify that you're a human before you can start your free trial. Follow the instructions on the screen.

Next, Twilio will ask you some questions to customize your experience. You can either answer them or skip directly to the dashboard.

sign up dashboard

 

Once on the dashboard, you'll be able to access your Account SID, Auth Token, and purchase a Twilio phone number.

Like your other credentials, you will store your Twilio Account SID and Auth Token in your .env file. To do this, copy and paste the following text at the end of your .env file, and be sure to replace the placeholder values with your own:

export ACCOUNT_SID=yourAccountSID
export AUTH_TOKEN=yourAuthToken

Once you've created an account and have an SMS-enabled Twilio phone number, you can send and receive messages.  

At the end of your callback function, add the following code, taking care to replace the placeholder numbers in this code sample with your Twilio phone number for the from value and a number where you can receive SMS messages for the to value:


T.get('search/tweets', { q: 'looking for frontend', count: 100 }, async (err, data, response) => {
  ...

  const accountSid =  process.env.ACCOUNT_SID 
  const authToken  =  process.env.AUTH_TOKEN
  const client = require('twilio')(accountSid, authToken);

  client.messages
    .create({
      body: `Your tweets are ready for review! Happy Job Hunting!`,
      from: '+1234567890',
      to: '+1234567890'
    })
    .then(message => console.log('Message sent: ', message.sid));
});

Make sure to use E.164 formatting for the numbers: [+][country code][phone number including area code]

Let’s break down your code. Like you did for your Twitter configuration, you stored your Account SID and Auth Token as environment variables and loaded them from your .env file.

Next, you added the Twilio Node.js helper library you had installed earlier and passed in your Twilio credentials.

Using Twilio’s API, you created a new message. To do this, you needed a number to which you could send a message, a number from which you could send a message, and a message itself.

Lastly, let’s add error handling in case Twit throws an error. There are a couple of ways you can do this. Two options are that you can log the error in the console or you can send a failure text message. Here’s how you can do the latter.

Firstly, you will move your accountSid, authToken and client declarations to the top of the callback function, because you want to access these values in both your try and catch blocks. Next, you will add try and catch blocks. Except for the variable declarations, your try block is the same as you have seen before.

In your catch block, you will send another message. The only difference being the body of the message.

js 
T.get('search/tweets', { q: 'looking for frontend', count: 1 }, async (err, data, response) => {
   const accountSid = "AC3e621098e90fd7ca0165e6d0af386d55"; 
   const authToken  = "025459a9fb47dbab12221a374c31c8ef"; 
   const client = require('twilio')(accountSid, authToken);

   try {
     const statuses = data.statuses;
     const tweets = [];

     statuses.map(status => {
       tweets.push({
         time: status.created_at,
         text: status.text,
         name: status.user.name,
         screen_name: status.user.screen_name,
         tweet_url: `https://twitter.com/${status.user.screen_name}/status/${status.id_str}`
       });
   });

   const csv =  await new ObjectsToCsv(tweets);
   await csv.toDisk('./automatic.csv', { append: true });

   client.messages
     .create({
       body: `Your csv file is ready to review! Go Job Hunting! - ${new Date().toLocaleString()}`,
       from: '+12059645175',
       to: '+14086381617'
     })
     .then(message => console.log(message.sid));
   } catch(e){
     client.messages
     .create({
       body: `Oops! something is wrong - ${new Date().toLocaleString()}`,
       from: '+12059645175',
       to: '+14086381617'
     })
     .then(message => console.log(message.sid));
   }
 })

Whenever your code runs, not only will you get your tweets in a .csv format, but you will also get a text as a reminder.  

Conclusion

I've heard a saying; “if you find yourself doing something thrice, chances are you will do it again.” It's better to automate it.

Not only has this automation helped me find jobs, but it also boosted my portfolio. To make this script even more fun, you could try using Twit's post API to respond to a tweet utilizing this script. Or you can use Twit to create a bot that retweets all the tweets which contain specific keywords.

With Twitter's robust API and a bit of JavaScript, the possibilities are endless. Happy job hunting!