Slack Bot

Slack Bot
Python과 Slack API를 사용하여, 특정 채널에 자동으로 글을 올리거나 댓글을 달아주는 슬랙봇을 만들어보겠습니다.
두 개의 과정으로 진행되는데,
첫 번째는 Slack API에 bot을 등록하는 것이고
두 번째는 등록된 bot을 Python으로 활용하는 것입니다.
Slack API에 bot을 등록하는 것
Slack API에 접속하여 Create An App을 클릭합니다.

From scratch를 클릭합니다.

앱 이름을 작성하고, 슬랙 작업 환경을 선택한 후에 Create App을 클릭합니다.

Bots를 클릭합니다.

왼쪽 상단에는 입력한 앱 이름이 나오는 것을 확인할 수 있습니다.
Review Scopes to Add를 클릭하여 앱 관련 권한을 설정할 수 있습니다.

Install App to Workspace 버튼이 비활성화 되어있는데 적어도 하나의 권한(Scope)를 설정해야 활성화되는 것을 확인할 수 있습니다.

스크롤을 내리면 Scopes를 설정하는 부분이 나타납니다.  Bot Token Scopes 부분에 있는 Add an OAuth Scope버튼을 클릭하여 관련 권한을 설정하면 됩니다.
Slack API Methods에 가면 다양한 메소드를 확인하실 수 있습니다.

예를 들어, conversations.history라는 메소드를 클릭한 사진을 가져왔습니다.
이 메소드를 호출할 때 필요한 권한들이나 1분 동안 몇 번정도 호출할 수 있는지, Arguments, 사용법 등이 자세하게 설명되어 있는 것을 알 수 있습니다.  이 메소드의 경우 Rate limits가 Tier 3인데 클릭하면 자세한 정보가 나오고 50+ per minute 정도로 제한이 되는 것을 확인하실 수 있습니다.
이처럼 용도에 맞게 메소드를 선택하시고, 권한을 설정해주시면 될 것 같습니다.

권한을 설정하면 Install App to Workspace 버튼이 활성화되고, 클릭하여 허용 버튼을 누릅니다.

Bot User OAuth Token이 나오고, 나중에 Slack API를 호출할 때 사용되니 잘 저장해둡니다.

그리고 Slack Bot 앱을 원하는 채널에 추가해주면 됩니다.

등록된 bot을 Python으로 활용하는 것
slack_sdk 라이브러리를 사용할 것이기 때문에 터미널에서 아래 명령어로 설치합니다.
pip install slack_sdk__init__에서 아까 저장했던 token id를 WebClient 파라미터로 넣어줍니다.
get_channel_id 메소드는 channel 이름을 파라미터로 넘겨주면 channel id를 리턴해주는 메소드입니다.
여기서 conversations_list 메소드를 사용하는데, types로 “public_channel”을 넘겨주면 public 채널만 검색이 가능하고,
“private_channel”을 넘겨주면 bot이 추가되어있는 private 채널만 검색이 가능합니다.
from slack_sdk import WebClient
class SlackAPI:
    def __init__(self, token, channel_name):
        self.client = WebClient(token)
        self.channel_type = "public_channel"  # or "private_channel"
        self.channel_id = get_channel_id(channel_name)
        
    def get_channel_id(self, channel_name):
        result = self.client.conversations_list(types=[self.channel_type])
        channels = result['channels']
        channel = list(filter(lambda c: c["name"] == channel_name, channels))[0]
        channel_id = channel["id"]
        return channel_idget_message_ts 메소드는 conversations_history 메소드를 사용하여 메시지의 timestamp(ts)와 text 내용을 파싱하여 리턴해주는 함수입니다.
파라미터 oldest는 메시지 검색을 처음부터 하지말고 해당 시간부터 해달라고하는 파라미터입니다.
이 oldest 값을 계속 수정해주면 봇이 채널의 정보를 계속 가져올 때, 중복되지 않고 새로운 정보만 가져올 수 있도록 할 수 있습니다.
def get_message_ts(self, end_ts):
    message_info = list()
    result = self.client.conversations_history(channel=self.channel_id, oldest=end_ts)
    messages = result['messages']        
    for message in messages:
        message_ts = message["ts"]
        message_text = message["text"]
        message_info.append({"ts": message_ts, "text": message_text})
    return message_infopost_thread_message 메소드는 chat_postMessage 메소드를 사용하여 원하는 채널, 원하는 스레드(메시지)에 댓글을 달아주는 함수입니다.
파라미터로 thread_ts를 빼면, 원하는 채널에 스레드(메시지)를 남길 수 있습니다.
def post_thread_message(self, message_ts, text):
    self.client.chat_postMessage(
        channel=self.channel_id,
        text=text,
        thread_ts=message_ts
    )post_emoji 메소드는 reactions_add 메소드를 사용하여 원하는 채널, 원하는 스레드(메시지)에 이모지를 달아주는 함수입니다.
위의 post_thread_message 메소드와 같이 보통 여기서는 스레드(메시지)를 timestamp로 구분합니다.
여기서는 이모지 "smile"을 사용하였는데, 직접 만든 이모지 뿐만 아니라 등록되어 있는 이모지의 이름을 적어주시면 됩니다.
def post_emoji(self, message_ts):
    self.client.reactions_add(
        channel=self.channel_id,
        name="smile",
        timestamp=message_ts
    )최종적으로 다 합친 코드입니다.
from slack_sdk import WebClient
class SlackAPI:
    def __init__(self, token, channel_name):
        self.client = WebClient(token)
        self.channel_type = "public_channel"  # or "private_channel"
        self.channel_id = get_channel_id(channel_name)
        
    def get_channel_id(self, channel_name):
        result = self.client.conversations_list(types=[self.channel_type])
        channels = result['channels']
        channel = list(filter(lambda c: c["name"] == channel_name, channels))[0]
        channel_id = channel["id"]
        return channel_id
        
    def get_message_ts(self, end_ts):
        message_info = list()
        result = self.client.conversations_history(channel=self.channel_id, oldest=end_ts)
        
        messages = result['messages']        
        for message in messages:
            message_ts = message["ts"]
            message_text = message["text"]
            message_info.append({"ts": message_ts, "text": message_text})
        return message_info
    def post_thread_message(self, message_ts, text):
        self.client.chat_postMessage(
            channel=self.channel_id,
            text=text,
            thread_ts=message_ts
        )
       
    def post_emoji(self, message_ts):
        self.client.reactions_add(
            channel=self.channel_id,
            name="smile",
            timestamp=message_ts
        )Reference
Subscribe to SOOFTWARE
Get the latest posts delivered right to your inbox