DEV Community

Cover image for The one where we build a web scrapper and a slackbot - Part 2
Victory Akaniru
Victory Akaniru

Posted on

The one where we build a web scrapper and a slackbot - Part 2

The problem

In part one of this two-part series we set out on a quest to automate these tasks

  • Visit Brainyquote
  • Find and copy a random quote about excellence from the site.
  • Post the quote to a slack channel.

we were able to build a web scraper that enabled us to scrape a website for quotes and save them to a JSON file. In this second part of the article series, we would be bringing it all together by building a slackbot that would periodically post one of the quotes we scrapped to a slack channel!

If you missed part one you can find it here

The Product

  • Slackbot: Here we would visit slack apps page, and create a bot associated with a slack channel.
  • Slackapi backend: Making use of slacks open API we would write some python functions that when called posts the message to a channel.
  • Apscheduler: Finally we would write another function that would help us call those API functions at intervals.

Prerequisites

  • Building up from part one, all you'll need at this point is a slack workspace, you could easily create one for free here or just build the bot into any workspace by creating a channel where you can play around with.

Part 2: The slackbot

To get started visit slack a modal should pop up like this Alt Text

  • Type in your app name
  • Select a development workspace(slack workspace where the bot would be installed)
  • Click create App and you'll be navigated to this page Alt Text

  • Now we need to set a scope for our bot

    Scopes give your bot permission to do things like sending a message in your development workspace.

  • Navigate to OAuth & Permissions on the sidebar to add scopes to your app

  • Scroll down to the Bot Token Scopes section and click Add an OAuth Scope.

  • Select or search for chat:write scope to grant your bot the permission to post messages in channels it's a member of. you should see a success banner after this ✅

  • Next, we have to install the bot to our workspace, by scrolling to the top of the OAuth & Permissions pages and clicking the green Install App to Workspace button.

  • After the above step, you should be navigated to the below page. All you have to do is click the allow button.
    Alt Text

  • Finally 🎉, copy your bot token, you'll need it to communicate with slack API.

Next steps... We need to write our backend code to interface with slack. we will be doing this in the same folder where we created our web scrapper you can find that code if you don't have it by clicking here

- cd clonedOrExistingProject
- mkdir bot
- cd scrapping-tool
- touch __init__.py builder.py post_message.py
Enter fullscreen mode Exit fullscreen mode

Create and activate a virtual environment if you don't have one already

- virtualenv --python=python3 venv
- source venv/bin/activate
Enter fullscreen mode Exit fullscreen mode

In the builder.py file add the following code

def construct_payload(HEADER_BLOCK, DIVIDER_BLOCK, MESSAGE_BLOCK):

    return {
        "channel": "your-channel-id-goes-here",
        "username": "name-of-your-app",
        "icon_emoji": ":robot_face:",
        "text": ":wave: Your daily dose of motivation has arrived",
        "blocks": [
            HEADER_BLOCK,
            DIVIDER_BLOCK,
            MESSAGE_BLOCK
        ],
    }

Enter fullscreen mode Exit fullscreen mode

Slack has a tool called the block builder kit, it's basically used to generate markdowns that can be used to style the appearance of messages on slack. Try it out here.

For us, we created a function that accepts various blocks from the block builder kit and in the end, we want to have something looking like thisAlt Text

From the code, we passed in

  • Channel: The id of a Slack channel where we want to invite our bot(you can copy it from your slack channel, make sure to invite the bot to this channel)
  • Username: which would be the name of the app you created earlier
  • Text: would be what appears on the slack notification popup.
  • Blocks: contains the various parts of the message, the header, a divider line, and the actual message.

Let's start by creating our random quote generator function, this file will read our previously scrapped json quotes and return any random one when the function is called. from the root of your project folder, run the command

- mkdir utils
- touch __init__.py random_quote.py
Enter fullscreen mode Exit fullscreen mode

In the random_quote file, add the following code

import random
import json


def random_quotes_generator():
    with open('quotes.json', 'r') as f:
        quotes_dict = json.load(f)


        quote = random.choice(quotes_dict)
        return quote

Enter fullscreen mode Exit fullscreen mode

This file creates a function random_quotes_generator reads our quotes from the json file and with python's random module returns one random quote when called.

Next, we create our post message function. Install these packages

pip3 install slack dotenv
Enter fullscreen mode Exit fullscreen mode

slack to interface with slack API and dotenv to load in our bot secret token.

Navigate to the post_message.py file and post the following code.

import os
from slack import WebClient
from dotenv import load_dotenv
from bot.builder import construct_payload
from utils.random_quote  import random_quotes_generator

load_dotenv()

SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")

# Initialize a Web API client
slack_web_client = WebClient(token=SLACK_BOT_TOKEN)


def post_quote_to_channel():
    quote = random_quotes_generator()
    author = quote['author']
    link = f"https://www.brainyquote.com{quote['author-link']}"


    # Get the onboarding message payload
    message = construct_payload({
        "type": "section",
        "text": {
                "type": "mrkdwn",
                "text": "*Your daily dose of motivation* :blush:"
        }
    },
        {
        "type": "divider"
    },
        {
        "type": "section",
        "text": {
            "type": "mrkdwn",
            "text": f"The test of the artist does not lie in the will with which he goes to work, but in the excellence of the work he produces... *By <{link}|{author}>*"
        }
    })
    # Post the onboarding message in Slack
    response = slack_web_client.chat_postMessage(**message)

Enter fullscreen mode Exit fullscreen mode

So what are we doing here...

We imported a couple of 3rd party packages, our message builder function and our random_quotes_generator.

We also load in our SLACK_BOT_TOKEN, create a .env file use the key SLACK_BOT_TOKEN and set it to your bot token.

SLACK_BOT_TOKEN=token
Enter fullscreen mode Exit fullscreen mode
  • We initialized slack WebClient and created the post_quote_to_channel inside which we call our random generator function and save it to a variable quote.
  • We construct a link to each author's page.
  • Next, we construct our message by calling the construct_payload function exported from the message builder file and passing in all required parameters.
  • Finally, we call a function chat_postMessage from slack WebClient and pass in our constructed message.

You can test that this works now by calling the function on your terminal running this command

python3 post_message.py
Enter fullscreen mode Exit fullscreen mode

The final step in this process would be to create our scheduler to periodically call the post_quote_to_channel. to do this we need to install some packages, create a flask server and our scheduler function.

On the root of your project folder create a new file app.py and run the following commands

pip3 install APScheduler Flask
Enter fullscreen mode Exit fullscreen mode
- cd bot
- mkdir jobs
- touch __init__.py scheduler.py
Enter fullscreen mode Exit fullscreen mode

In bot/jobs folder locate the scheduler.py file and paste in the following code

from apscheduler.schedulers.background import BackgroundScheduler

# jobs
from bot.post_message import post_quote_to_channel

scheduler = BackgroundScheduler()

scheduler.add_job(
    post_quote_to_channel,
    'interval',
    seconds=10
)
Enter fullscreen mode Exit fullscreen mode

Here we import BackgroundScheduler from the scheduler package and initialize it.

  • We also import the post_quote_to_channel function from the file post_message in the bot folder.
  • With that, we call add_job function from the scheduler, pass the post_quote_to_channel function, the string interval and time interval in seconds. to read more about app scheduler click here

with that, we have our scheduler function ready.

Bringing it all together

In the app.py file we created earlier, post the following code

import os
import time
from flask import Flask
from bot.jobs.scheduler import scheduler

# Initialize a Flask app to host the events adapter
app = Flask(__name__)

if __name__ == "__main__":
    scheduler.start()
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))

    try:
        # This is here to simulate application activity (which keeps the main thread alive).
        while True:
            time.sleep(5)
    except (KeyboardInterrupt, SystemExit):
        # Not strictly necessary if daemonic mode is enabled but should be done if possible
        scheduler.shutdown()

Enter fullscreen mode Exit fullscreen mode

Here we import our scheduler, create a flask server and call our scheduler function. we also use a nifty trick from StackOverflow to keep our main thread alive.

Run the program

python app.py
Enter fullscreen mode Exit fullscreen mode

If we've done everything right we would start receiving quotes in our slack channel every 10 seconds.

You can tweet the time interval to suit your needs. e.g minutes=69 || hours=24

That's it guys, through these series we've been able to cover a few micro-skills

  • building a slackbot
  • scraping a website
  • scheduling tasks

These skills can be applied separately or brought together to build a cool product.

I'll like to hear your feedback and question, feel free to leave a comment.

To view the full code click here

Top comments (2)

Collapse
 
dansteve profile image
Dansteve Adekanbi

Very useful.

Collapse
 
vic3king profile image
Victory Akaniru

Thank you!