Profile picture

[Python] 파이썬으로 나에게 카카오톡 메시지 보내기

JaehyoJJAng2023년 06월 08일

만드는 이유

매일 일정한 시간에 크롤링 되는 데이터를 카카오톡으로 전송해보기 위해서 해당 게시글을 작성하게 되었다.

목표를 위한 대략적인 순서는 다음과 같다.

  • kakao developers 가입
  • 메시지 보낼 애플리케이션 생성
  • REST API 확인
  • 카카오 로그인 설정 및 메시지 보내기 허용하기
  • 개인 고유 코드 확인 (유효시간 있음)
  • 인증 Token 발급
  • 파이썬 코드로 메시지 보내기

1. Kakao Developer 가입

아래 URL에 들어가서 가입을 해주도록 하자. (가입하는 과정은 생략)
https://developers.kakao.com/


2. 애플리케이션 생성

로그인을 했으면 "내 애플리케이션" 으로 들어가서 애플리케이션을 추가해주도록 하자. (나의 경우 이미 추가되어 있음.)
image
앱 이름 및 사업자명은 사용자가 원하는 이름으로 설정해주면 된다.


3. REST API 확인

생성된 애플리케이션을 클릭하면 아래와 같은 항목이 표시될텐데 여기서 REST API 값만 확인하면 된다. (메모장이나 서버 환경 변수에 기록/등록해주자.)
image
참고로 REST API 값은 애플리케이션별로 고정되어 있다.


4. 카카오 로그인 설정

REST API 확인이 끝났으면 카카오 로그인 설정을 해주도록 하자.
image
카카오 로그인 항목으로 간 후 활성화 상태를 "ON"으로 변경해주자.

그리고 Redirect URI는 샘플로 제공되는 주소로 설정해도 무방하다. (사용자가 원하는 주소로 설정해도 상관 없음.)
나는 샘플로 제공되는 주소인 https://example.com/oauth로 설정하였다.


5. 메시지 보내기 허용

그 뒤에 "동의 항목"으로 들어가서 접근권한 섹션에 "카카오톡 메시지 전송" 항목을 선택 동의로 바꿔주도록 하자.
image

6. 개인 고유 코드 확인

이제 고유 코드를 발급 받아보도록 하자.

위 과정이 문제 없이 진행되었다면 아까 확인해둔 REST API 값을 가지고 Code 값을 부여받아야 한다.
아래 URL에 자신의 REST API 키 값과 설정했던 Redirect URI 값을 입력해주자.

https://kauth.kakao.com/oauth/authorize?client_id=자신의 REST 키값&redirect_uri=REDIRECT로 설정했던값&response_type=code

최초 수행시에는 카카오 로그인 창이 뜨며 동의 여부를 묻는다.
나처럼 Redirect URI을 https://www.example.com/oauth로 설정하고 위 과정들을 수행했다면 다음과 같은 화면이 뜰 것이다.
image
모자이크 처리 해놓은 부분인 code=<고유 코드>의 값들이 필요하다.

🔺

참고로 해당 값은 위의 과정을 수행할 때마다 새로 발급되므로 마지막에 수행했던 최신 값만 유효하다
(이후에 토큰 값을 자동으로 발행하는 과정도 알아볼 것이다.)


이제 파이썬 코드를 통해 카카오톡에 메시지를 보낼 수 있는 인증 토큰을 발행받고, 그 토큰을 이용해 카카오톡 메시지를 보내보자.


7. 토큰 생성하기

먼저 토큰을 발급 받아 JSON 형태로 저장하는 코드이다.

from src.utils.get_secrets import get_secrets
import requests as rq
import json

URL : str = 'https://kauth.kakao.com/oauth/token'
REDIRECT_URI : str = 'https://www.example.com/oauth'
CODE : str = '4m60TXARd7Y9hT8YJODSYRf0oRShkmt8_mbZSqbl6vomrCc9XZSvJgBd4fUKKclgAAABi39AlxoBl6J2VXah6g'
CLIENT_ID : str = get_secrets()('CLIENT_ID')

def create_token() -> None:
    data : dict[str,str] = {
        'grant_type':'authorization_code',
        'client_id':CLIENT_ID,
        'redirect_uri':REDIRECT_URI,
        'code': CODE,
        }
    
    response : rq.Response = rq.post(url=URL,data=data)
    
    if response.status_code != 200:
        print({"Message": f"Error! because {response.json()}"})
    else:
        tokens = response.json()
        with open('token.json','w') as fp:
            json.dump(tokens,fp)

정상적으로 스크립트가 실행되었다면 아래처럼 'token.json' 파일이 생성되고 해당 파일에는 아래 내용이 포함되어 있어야 한다.

$ ls -lh token.json
-rw-r--r--  1 jaehyolee  staff   272B 10 30 15:23 token.json

$ cat token.json
{"access_token": "cELZxxxxxxxxx", "token_type": "bearer", "refresh_token": "Z8pxxxxxxx", "expires_in": 21599, "scope": "talk_message", "refresh_token_expires_in": 5183999}

🔺 Infos

TOKEN을 발급 받았다면 이후부터는 인증 코드를 발급 받을 필요가 없어진다. 이제부턴 계속 해당 토큰을 사용하면 된다.


8. 토큰 관리하기 (토큰 자동 발행 코드)

위에서 발급한 token을 계속 사용해야 한다. 아래의 함수를 각각 만들고, 토큰 저장 함수를 호출하도록 하자.

  • kakao_token.json 파일에 토큰을 저장하는 함수
  • 저장된 파일에서 토큰 값을 읽어오는 함수
  • 토큰 갱신 함수

토큰은 kakao_token.json 파일에 저장되고, 해당 파일은 kakao_env/ 폴더에 저장된다.


token_manage.py

from src.utils.get_secrets import get_secrets
import json
import requests as rq
import datetime
import os

class TokenManage():
    def __init__(self) -> None:
        # 카카오 토큰 저장할 파일명
        self.KAKAO_TOKEN_FILENAME : str = 'kakao_env/kakao_token.json'
        self.app_key : str = get_secrets()('CLIENT_ID')

    def save_tokens(self,tokens : dict[str,str | int]) -> None:
        """ 토큰 저장하는 메서드 """
        with open(self.KAKAO_TOKEN_FILENAME,'w') as fp:
            json.dump(tokens,fp)
    
    def load_tokens(self) -> dict[str,str | int]:
        """ 토큰 읽어오는 메서드 """
        with open(self.KAKAO_TOKEN_FILENAME,'r') as fp:
            tokens = json.load(fp)
        return tokens

    def update_tokens(self) -> dict[str,str | int]:
        """ refresh_token 으로 access_token 갱신하는 메서드 """
        tokens : dict[str,str | int]= self.load_tokens()
        
        url : str = 'https://kauth.kakao.com/oauth/token'
        
        data : dict[str,str] = {
            'grant_type': 'refresh_token',
            'client_id': self.app_key,
            'refresh_token': tokens['refresh_token']
        }
        response : rq.Response = rq.post(url=url,data=data)
        
        if response.status_code != 200:
            print({'Message': f'error! because {response.json()}'})
        else:            
            # 기존 파일 백업
            now : str = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
            backup_filename : str = self.KAKAO_TOKEN_FILENAME + now
            os.rename(self.KAKAO_TOKEN_FILENAME,backup_filename)
            
            # 갱신된 토큰 저장
            tokens['access_token'] = response.json()['access_token']
        return tokens

9. 카카오톡 메시지 보내기

이제 토큰 관리는 끝났고 저장되어 있는 token 정보를 가지고 메시지를 보내는 코드를 알아보자.


kakaotalk_message.py

from src.token.token_manage import TokenManage
import requests as rq
import json

class Message():
    def __init__(self) -> None:
        # TokenManage Instance
        self.tokenManage : TokenManage = TokenManage()
        
        self.url : str = 'https://kapi.kakao.com/v2/api/talk/memo/default/send'

    def set_headers(self) -> None:
        tokens : dict[str,str | int] = self.tokenManage.load_tokens()
        self.headers : dict[str,str] = {
            "Authorization" : "Bearer " + tokens["access_token"]
        }
    
    def send(self,text: str) -> None:
        # Headers 지정
        self.set_headers()
        
        data = {
            'object_type': 'text',
            'text': text,
            'link': {
                'web_url': 'https://developers.kakao.com',
                'mobile_web_url': 'https://developers.kakao.com'
            },
            'button_title': '키워드'
        }
        data = {'template_object': json.dumps(data)}
        response = rq.post(url=self.url,headers=self.headers,data=data)
        
        if response.status_code != 200:
            print({'Message': f'error! because {response.json()}'})
        else:
            print(response.json())

마무리

가장 치명적인 단점은 "나에게 보내는 메시지"는 알람이 울리지 않는다는 것이다.
학습차 공부해보기는 했으나 이럴바에는 그냥 슬랙을 쓰는게 낫겠다.


Loading script...