특정 키워드 뉴스 카카오톡 자동 발송 구축하기 - (1)
여느 날과 같이 집에서 저녁을 먹다가 와이프가 갑자기 나에게 한가지를 물어보았다.
"자기야 특정 뉴스 매일 카톡으로 오면 좋겠는데 그런 기능은 없어?"
자존심으로 똘똘뭉친 나는 "아니? 그런게 왜 없어 당연히 있지 내가 만들어줄게!" 라고 호언 장담하였다.
그렇게... 해당 서비스는 제 와이프의 요청으로 인해서 구축하게 되었습니다.
(이상 배경 설명 끝)
먼저, 이전에 설명한 Naver News API 를 먼저 참고하고 오시면 좋을 것 같다.
네이버 뉴스 API 정리
특정 키워드 관련 뉴스들을 모니터링 하기 위해 네이버 api 로 뉴스를 가져오는 방법을 소개하고자 한다. https://developers.naver.com/main/ NAVER Developers 네이버 오픈 API들을 활용해 개발자들이 다양한
ds92.tistory.com
가장 먼저 개발하는 순서는 아래와 같았다.
1. Naver News API
- 특정 키워드 뉴스
- 중복 기사 검증
2. Kakao API ( 카카오톡 메시지 발송 )
3. 자동화
1번은 위 이전 게시물을 기반으로 가져와서 여러 키워드로 조회해 보았다.
위 사진과 같이 동일한 뉴스 내용의 기사들이 존재하는 것을 볼 수 있었다.
단순한 중복제거로는 제거가 되지 않을 것 같아서 텍스트 유사도 분석을 통해 유사도가 높은 것을 제거하는 로직을 추가하였다.
텍스트 유사도는 자카드 유사도 분석법을 사용하였다.
자카드 지수(Jaccard index) 란?
-> 두 집합 사이의 유사도를 측정하는 방법 중 하나이다. 자카드 계수(Jaccard coefficient) 또는 자카드 유사도(Jaccard similarity)라고도 한다. 자카드 지수는 0과 1 사이의 값을 가지며, 두 집합이 동일하면 1의 값을 가지고, 공통의 원소가 하나도 없으면 0의 값을 가진다. 자카드 지수는 아래의 식으로 정의된다.
위에서 가져온 뉴스 기사들을 토대로 자카드 지수를 각 기사별로 구해서 유사도가 0.3 이하인 것들만 추출했다.
# 자카드 유사도 함수 정의
def jaccard_similarity(s1, s2):
s1, s2 = set(s1.split()), set(s2.split())
return float(len(s1 & s2)) / len(s1 | s2)
# 유사도 계산 및 중복 제거
# 전처리
today_df['title2'] = today_df['title'].apply(lambda x : re.sub(r"[^\w\s\'\"]", "", x))
today_df2 = today_df.copy()
# threshold = 0.3 # 유사도 임계값 설정
for std_title in list(today_df['title2']) :
today_df2['jaccard'] = today_df2['title2'].apply(lambda x : jaccard_similarity(std_title, x))
today_df2 = today_df2.loc[(today_df2['jaccard'] <= 0.3) |
(today_df2['jaccard'] == 1)
].reset_index(drop=True)
이후 해당 today_df2라는 DataFrame을 기준으로 제목과 링크를 각각 하나의 텍스트로 취합해서 프린트를 해보았다.
제목을 보듯이 아주 조금 겹치는 부분이 존재하지만, 기존 것들보다 중복 내용 기사가 엄청 많이 줄어든 것을 확인할 수 있었다.
이제 보낼 콘텐츠(텍스트)는 완성이 되었다.
이후, 이제 카카오 톡으로 자동 발송을 해야하는 상황이다.
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
이번 기회에 처음으로 OAuth2.0 를 살펴볼 수 있었다.
기존에 accese key 만 필요했던 API랑은 다르게 많은 인증이 필요했다.
간략하게 설명하면 access token을 발급받을 때 refresh token 도 같이 발급이 된다.
access token은 일정 기간이 지나면 유효하지 않은 값으로 변하기 때문에 일정 기간이 지나기 전에 refresh_token을 이용해서 해당 access token을 refresh 해줘야한다.
import requests
import json
refresh_token = '처음 얻은 refresh token'
headers={"Content-Type" : "application/x-www-form-urlencoded "}
url = 'https://kauth.kakao.com/oauth/token'
rest_api_key = '본인 키'
redirect_uri = '본인 uri'
client_secret = '본인 client secret key'
data = {
'grant_type':'refresh_token',
'client_id': rest_api_key,
'refresh_token': refresh_token,
'client_secret' : client_secret
}
response = requests.post(url, headers=headers, data=data)
tokens = response.json()
# print(tokens)
access_token = tokens['access_token']
위 코드를 통해서 refresh_token 을 활용해서 access_token을 발급받아서 사용하는 구조로 보면 된다.
그렇게 refresh_token을 API를 통해 재등록(?)하고 나서 얻은 access_token을 활용하여 카카오톡 메시지를 전송하면 된다.
나에게 보내기 말고, 타인에게 보내기를 할 경우에는 특정 대상자의 여러 동의가 필요하다.
내 케이스는 그냥 나에게 보내고 전달해주는 식으로 베타 테스트를 진행했다.
# 텍스트 전송
url="https://kapi.kakao.com/v2/api/talk/memo/default/send"
headers={
"Authorization" : "Bearer " + access_token
}
data={
"template_object": json.dumps({
"object_type":"text",
"text":final_text,
"link":{
"web_url":"www.naver.com"
}
})
}
response = requests.post(url, headers=headers, data=data)
if response.json().get('result_code') == 0:
print('메시지를 성공적으로 보냈습니다.')
else:
print('메시지를 성공적으로 보내지 못했습니다. 오류메시지 : ' + str(response.json()))
위 코드에서 말하는 final_text 는 제목과 링크를 조합했던 하나의 발송 콘텐츠를 의미한다.
다음 게시글에서 해당 메시지를 자동으로 특정 시간에 발송되는 것을 설정하는 방법을 설명하고자 한다.