걸어서 개발속으로

1.약 먹었는지 물어보고 체크해주는 기능을 만들어 보자! (1) 본문

Side Project/트위터 봇 제작기

1.약 먹었는지 물어보고 체크해주는 기능을 만들어 보자! (1)

티샤 2022. 8. 23. 01:27

사용언어 : Python

사용툴 : Pycharm

사용DB : 일단은 구글 스프레드시트..이나 추후 변경될수도.


0.왜 만들려고 하는가? 

아침 저녁으로 약을 먹는 평범한 성인 @인 당사자. 하지만 종종 약을 까먹는 경우가 생겨버리고 마는데!

물론 우리에겐 알람과 약 먹을때를 알려주는 어플 등등, 편리한 기능을 가진 프로그램들이 참 많지만

사실 그 모든 것이 귀찮았고, 진성 트위터리안은 이 모든 것을 트위터로 해결하고 싶어했다.

 

1.내가 생각한 작동원리는?

 

(1)매일 일정 시간 되면 약 먹었냐고 봇이 물어봄

(2)[명령어] 약 먹었다! 하면

(3)연동db에 약 먹은거 자동으로 기재함

(4) 매달 자동으로 얼마나 잘 챙겨먹었는지 그래프(?)화 하기 (여기까지 할 수 있는가?)

 

그렇게 Pycharm 을 켰다. 


2.(1)매일 일정 시간 되면 약 먹었냐고 봇이 물어봄

 이 기능을 구현하려면 가장 먼저 내가 구현해야하는 기능은...  "특정 시간이 되면 알람을 울려보자." 가 된다.

 그 당시 가장 만만하게 보였던 모듈은 datetime이었는데, 

 

If nowtime.minute == 54: 
    print("54분이에용!")

...라고 생각했다가, 이 방법은 아니라는 것만 깨닫고 왔다.

그래. 쉬울리가 없지! 하고 구글링을 시작했다.

 

수많은 검색과 수많은 기술 블로그들을 보며..

당시 나의 검색어는 [파이썬 알람] [파이썬 알람봇] ...

(왜 영어로 검색하지 않았는가. 일단 한국인이니 한글로 된 글을 찾으면 이득이다)

백준 알람시계 문제만 보며 절망하다가 우연히 포스팅 하나를 발견.

https://dev-woody.tistory.com/73

 

파이썬 스케쥴러 설정하기

파이썬에서는  특정시간마다 프로그램을 돌릴 수 있는 스케쥴러를 제공한다. 정기적으로 특정 시간이나 특정날짜에 스케줄링 할 수 있으며, 외부 의존성 없이 매우 간단하게 사용이 가능하다.

dev-woody.tistory.com

파이썬에는 특정시간마다 프로그램을 돌릴 수 있는 스케쥴러를 제공한다는 단비같은 소식!

바로 schedule 이라는 모듈을 사용하는 것이다.

사용법 또한 매우 직관적이었기에 바로 활용해보았다.

 

오전 8시와 오후 11시에 알람을 주게끔 코드를 짜보았다.

 

def alarm_8am():
    print("!아침 약 먹을 시간이에요!")


def alarm_11pm():
    print("!저녁 약 먹을 시간이에요!")


schedule.every().day.at("08:00").do(alarm_8am)  # 매일 오전 8시에 알람이 울린다
schedule.every().day.at("23:00").do(alarm_11pm)  # 매일 오후 11시에 알람이 울린다

while True:
    schedule.run_pending()
    time.sleep(10)

그렇게 멋지게 알람 구현을 해낸 나는 다음 스텝으로 넘어갔다. 바로 시간이 되면 트위터 알람을 보내는 설정!

tweepy를 이용해서 간편하게 구현해냈다.

import tweepy
import scheduler
import time
import datetime

def formtime():
    now = datetime.datetime.now()
    nowDatetime = now.strftime('%Y-%m-%d %H:%M:%S')
    return nowDatetime #중복 방지용 시간 기재

def alarm_8am():
    print("!아침 약 먹을 시간이에요!")
    reply = "@" + "본계아이디" + " "
    reply_contents = "아침 약 챙겼나요?" + "\n\n" + formtime()
    reply_result = reply + reply_contents
    api.update_status(reply_result)


def alarm_11pm():
    print("!저녁 약 먹을 시간이에요!")
    reply = "@" + "본계아이디" + " "
    reply_contents = "저녁 약 챙겼나요?" + "\n\n" + formtime()
    reply_result = reply + reply_contents
    api.update_status(reply_result)


schedule.every().day.at("08:00").do(alarm_8am)  # 매일 오전 8시에 알람이 울린다
schedule.every().day.at("23:00").do(alarm_11pm)  # 매일 오후 11시에 알람이 울린다

while True:
    schedule.run_pending()
    time.sleep(10)

이렇게 작성해서 실행하면... 

 

 

시간이 되었을 때, 이렇게 알람이 온다!

(*참고로  트윗 시간이 다른 이유는 알람테스트를 위해 시간을 임의로 조정했기 때문입니다...)

그렇다면, 이제 다음스텝으로 넘어갈 때가 됐다.

 

3.(2)[명령어] 약 먹었다! 하면 반응하기 (1/2)

나는 명령어 [약먹기] 를 넣으면, 참 잘했어요! 같은 칭찬으로 답멘을 해주고 > 스프레드시트에 기재...! 까지 시도하려고 했다.

그러려면 이것또한 기능을 쪼개서 차근차근 구현해야 했음.

 1)답 멘션에 키워드 [약먹기]가 있으면 "훌륭해요!" 라고 답변을 해준다

 2)답변을 하며 동시에 스프레드 시트에 기재

그러면 일단 1)답 멘션에 키워드 [약먹기]가 있으면 "훌륭해요!" 라고 답변을 해준다. 부터 구현해보기로 했다.

이건 키워드 봇과 비슷한 방식이라서, 크게 어려운 방식은 아니었다.

 

[봇의 멘션 타임라인을 불러옴 > 멘션 하나하나를 객체로 받고 > 객체 내용에 [약먹기] 가 있으면 > 답변하기!] 

하나의 패턴이므로... 이는 무난하게 구현을 했는데,

일단 멘션창을 확인하고 키워드 확인하는 함수는 사전에 구현해둔 것이 있어서 걔네를 다시 불러오고(울궈먹기 대장)

키워드를 추가했다.

 

def check_new_mention():
    print("!멘션을 확인하는 함수입니다")
    global last_reply_id
    mention_return = api.mentions_timeline(since_id=last_reply_id)  # 멘션창을 불러온다.
    mention_timeline_length = len(mention_return)  # len을 하는 이유는 답멘한거 이후로 빼야해서 그런거구나!
    for i in mention_return:
        print(i)
    print(mention_timeline_length)
    if mention_timeline_length > 0:
        print("!키워드 체크 함수 소환이다!")
        check_keyword(mention_timeline_length, mention_return)
        print("!다음 동작 기다리기")
        return
    print("!새 멘션이 없다요")


def check_keyword(mention_timeline_length, mention_return):
    global last_reply_id
    print("!키워드 체크 함수입니다")
    keyword = "[약먹기]"
    for i in range(mention_timeline_length - 1, -1, -1):
        mention = mention_return[i]
        mention_text = mention.text
        print(mention_text)
        try:
            if mention.author.id != bot_id:  # 내가 보낸 멘션이 아닐때만 답변하기
                if keyword in mention_text:
                    print("!약을 먹었어요")
                    reply_fir = "약을 잘 챙겼군요, 훌륭해요!" +"\n" + "DB 업데이트 완료"
                    reply_result = reply + reply_fir
                    api.update_status(result, in_reply_to_status_id=mention.id_str)
                    last_reply_id = mention.id_str
                    print("!문제 없이 작동했어요")

                else:
                    print("키워드가 없어용")
        except:
            print("!오류래용")
            pass

이랬는데...

 

자꾸 답멘이 안가는거다.

분명에 api.update_status의 in_reply_to_status_id는 바로 전에 받은 멘션의 계정 id값이 들어오는 걸 확인했는데,

답멘을 안달고 자꾸 일반트윗을 하는거다.

 

..그렇게 이전에 했던 나의 코드를 살펴보니,

if keyword in mention_text:
    print("!약을 먹었어요")
    reply = "@" + mention.user.screen_name + " "
    reply_fir = "약을 잘 챙겼군요, 훌륭해요!" +"\n" + "DB 업데이트 완료"
    reply_result = reply + reply_fir + "\n\n"
    result = reply_result + formtime()
    api.update_status(result, in_reply_to_status_id=mention.id_str)
    last_reply_id = mention.id_str
    print("!문제 없이 작동했어요")

.... 답변할때의 양식을 아예 누락한 점이었다.

트위터의 원래 답변 양식은 @계정아이디 "참 잘했어요" 의 느낌인데, @계정아이디 를 누락해버리니, 답멘을 하고 싶어도 양식에 어긋나서 일반트윗을 해버린거다..

그렇게 답변까지 훌륭하게 받아내는데 성공하며, 두번째 스텝으로 넘어갔다.

 

 2)[명령어] 약 먹었다! 하면 반응하기 - 답변을 하며 동시에 스프레드 시트에 기재 (2/2)

최후엔 DB를 이용할 듯 싶지만, 지금의 나는 스프레드시트가 가장 쓸만했는데,

일단 나는 아직 DB가 능숙치 않았고 gspread 활용을 잘 해서 마스터해보고 싶은 것도 있었다.

거기다가 그래프화까지? 그러면 엑셀이 답 아냐? (아닙니다) 라는 생각에 일단 스프레드시트에 구현해보기로 했다.

임의로 시트를 하나 만들고 어떻게 만들까 곰곰... 해보았다.

 

 그래서 내가 생각한 동작원리는...  

  1.명령어 [약먹기]가 들어온 날짜 [월 / 일 ] 구분해서 시트 이동

  2.시트의 A행에 적힌 숫자와 날짜의 [일]을 비교해서 동일하면 그 [열]을 사용함

  3.약 먹었냐고 물어본 트윗의 시간이 오전이면 [아침 약], 오후면 [저녁 약]으로 구분

  4.그렇게 해서.. 체크하기..? ('O'라는 문자를 넣고 조건부서식을 넣어서 색칠해줄까 했었다.)

  5.이왕이면 매 달 만들어지는 시트는 ... 월말 될 때마다 새로 하나씩 추가되는 어쩌고저쩌고?? ... 라고까지 생각하다 과부하걸림. 

 

 그래서 이 이상 해보려다가... 매일 2시간 코딩하기의 시간이 종료되었으므로 (..ㅋㅋ) 다음날로 넘기기로 했다... 

Comments