Mateo Mejia

Fullstack web developer, product person, mountain biking aficionado, languages nerd, a little obsessed with security.

Scraping Facebook birthdays with a Chrome extension

January 21, 2021

It’s 2021 and I still haven’t published my first project, so I decided I was going to pick one project from the backlog and actually start developing it, and the one being chosen was the Facebook Birthday Chrome Extension!

How the idea started

As someone who is very forgetful about birthdays I see Facebook as a tool that helps reminds me of my friend’s birthdays, the only problem is that I need to log in to see them, and I don’t visit the site very often, they also don’t have a way of downloading all the data, therefore I’ll make my own way.

Why a Chrome Extension

The main reason was that I had never developed one and just wanted to get my feet wet in this field. The other reason why this is useful is because you don’t need to authorize any external application to access your data in this black-box environment where you don’t know what they are doing with your data, they may claim to don’t store it, but do you really trust them?

In a Chrome extension, everything happens on your browser, and as I’m making this code open source, everyone can check what the program is actually doing. The perfect use case would be for someone to download the extension, export the birthdays, and delete the extension.

It’s an app made to be deleted and I think that’s beautiful in this world where privacy is more scarce by the day.

How to get started

When developing something you’ve never done before it helps to ask a friend. In my case I didn’t have any friends who knew about Chrome extensions so, I did the next best thing, I googled how to build a chrome extension. I skimmed the top results tutorials and came up with a plan.

1. Look for a boilerplate
2. Set up a development environment
3. Configure it so it works on the desired pages (facebook birthday url)
4. Use selectors to gather the data
5. Click a button to trigger the process

The boilerplate I found was called extensionizr, I selected what I thought I needed and didn’t check any permissions as I figured I could add them later. I added jQuery since I knew I had to do DOM element manipulation later and it’s just faster and easier with jQuery. Take into account that I’m a React developer and I wouldn’t use jQuery for a large application, but for this job, it was the perfect tool.

The next step is to go to Chrome extensions, click Load unpacked, and select the folder you get from extensionizr, now we have something installed that we can play around with.

Code on!

pro tip: use the mobile endpoint as it’s often much easier to scrape

I set my inject method to execute whenever the browser went to this site https://m.facebook.com/events/calendar/birthdays and ended up with a function that looks like this:

// first step is getting the root components
const birthdayScraper = async () => {
  console.log(`birthdayScraper starts running`);

  const allMonths = [];

  /**
   * The process here is quite simple.
   *
   * We get the next month, add its contents to the array.
   *
   * Check if allMonths.length == 12 - if yes then our work here is done.
   *
   * If allMonths.length < 12 then we save the current month, we scroll to bottom and we point the selector to the next node
   */

  //  const processMonth = throttle(getMonthBirthdayData, SCROLL_INTERVAL)

  let currentSelector = ROOT_SELECTOR;

  const executeLoop = () => {
    let articleTag = $.find(`${currentSelector} > article`);
    let monthNode = articleTag[0];

    if (!monthNode) {
      // this means the next month has not loaded so we double the buffer time and try again
      scrollToBottom();
      BUFFER_TIME = BUFFER_TIME * 2;
      setTimeout(() => executeLoop(), BUFFER_TIME);
      return;
    }

    console.log(`birthdayScraper getting month number ${allMonths.length}`);

    allMonths.push(monthNode.innerText);
    currentSelector = `${currentSelector} > div`;
    scrollToBottom();

    if (allMonths.length < 12) {
      setTimeout(() => executeLoop(), BUFFER_TIME);
    } else {
      processData(allMonths);
    }
  };

  // this triggers the first execution of the process
  setTimeout(() => executeLoop(), BUFFER_TIME);
};

Then I organized the data into an array for each Month and proceeded to export it.

Now, I wanted the users to have a choice to download in CSV too as JSON is too much geared towards developers…and a popup was made!

extension_popup

During all this time I consulted extensively the Get started page from Google Developers on chrome extensions.

Profit!

This is not true. We haven’t actually made a profit since the extension will collect no data about anyone.

But you will have a fresh file with all your friends’ birthdays so you never miss one again!

There’s a catch though. We only want to wish happy birthday to our closest friends and family members. Then, how can get only the people we care about enough? We can’t.

We have to manually go through each entry in order to find the ones we care about, going through this process made me realize how little I care for my Facebook friends’ birthdays and I didn’t add a single one of them to the calendar, I guess I’m not too big on birthdays.

That’s it for the story about the whole process, I hope you’ve enjoyed reading this piece and that it motivates you to pursue your projects.

Share This Post