트위터로 trpg/게임용 봇을 만들어보자 [2] 자동 응답하기

오터넛·2022년 5월 6일
0

※ 이번 글은 다음의 목차로 이루어져있습니다.
1. 코딩에 대한 기본적인 지식이 있는 분들/혹은 상세한 설명 없이 단지 코드를 사용하기 만하고 싶은 분들을 위한 간략한 요약문
2. 코딩에 대한 아무런 지식이 없는 초보자를 위한 입문글

💡 이 글에서 다루는 프로젝트 파일

src/main.py
src/tweetBot

1. 빠른 실행을 위한 간단한 설명

💡 본 코드는 트위터 api v1을 사용하여 작성되었습니다. v2에 비해 다소 조잡한 측명이 있지만 v2에서는 이미지 업로드 기능이 지원되지 않아 어쩔 수 없는 선택을 하였습니다. 후에 트위터에서 api v2에 이미지 업로드 기능을 추가하면 코드를 업데이트 할 예정입니다.

  1. main.py의 activity_list 에 사용하기를 원하는 키워드를 추가하거나 필요없는 키워드를 지운다.
    • activity_list 는 봇이 받을 명령어 목록입니다. 소스코드에 적힌 명령어들은 소스코드가 기본 제공해주는 명령어들입니다. 봇이 반응하기를 원하는 명령어를 추가하거나 삭제하세요.
    • 봇 기능에 대한 설명을 여기 를 확인하세요.
activity_list = ["오늘의운세", "[사냥]", "[요리]"]
  1. 새로운 키워드를 추가할 경우 src/tweetBot/update_tweet.py의 아래 코드 부분에 표기된 주석을 참고하여 기능을 추가하세요.

    elif task_name == "[일괄판매]":
        print("일괄판매 시작")
        num_c_equip = sheet_data["플레이어"][user_name].C급장비개수
        num_b_equip = sheet_data["플레이어"][user_name].B급장비개수
        if int(num_b_equip) + int(num_c_equip) == 0:
            reply_comment = "장비가 없습니다. 인벤토리를 확인해주세요."
        else:
            sell_total = 5000 * int(num_b_equip) + 1000 * int(num_c_equip)
            sheet_data["플레이어"][user_name].골드 += sell_total
            sheet_data["플레이어"][user_name].C급장비개수 = 0
            sheet_data["플레이어"][user_name].B급장비개수 = 0
            self.google_api.update_user_data("플레이어", "test", sheet_data["플레이어"])
            reply_comment = "@%s" % user_id + f"[장비판매]\nB급장비개수: {num_b_equip}\nC급장비개수: {num_c_equip}\n총가격: {str(sell_total)}"
    
    ##### 새로운 기능을 추가하길 바랄 경우 여기에 elif 구문으로 코드를 추가하세요 #####
    
    else:
        reply_comment = "@%s" % user_id + "봇 오류입니다. 캡쳐와 함께 총괄계에 문의 부탁드립니다."

💡 주의

  • 해당 함수는 키워드에 대한 '결과 텍스트'를 출력하는 함수로 elif에서는 결과물을 reply_comment 변수에 선언해주셔야 합니다.
  • 이때, comment는 답변을 받는 사용자 아이디 (user_id)를 포함합니다.
  1. 이미지를 첨부하고 싶을 경우 아래의 절차를 따라주세요
    1. 업로드하고자 하는 이미지를 src/tweetBot/images 폴더에 추가한다.
    2. reply_image 변수에 이미지명(확장자포함 ex. photo.png) string을 선언한다.
      예시 코드는 아래와 같습니다.
  reply_comment = "@%s" % user_id + "봇이 명령어를 읽었습니다."
  reply_image = "photo.png"

2. 입문자를 위한 자세한 설명

트위터 봇은 크게 세 가지 동작으로 이루어져 있습니다.

  1. 봇이 받은 멘션 불러오기
  2. 받은 멘션으로부터 키워드를 감지하기
  3. 키워드에 따른 결과물 출력하여 내보내기

그리고 이 글은 위의 순서에 따라 차례대로 코드를 설명합니다.

1. 봇이 받은 멘션 불러오기

이전 게시물에서 트위터에 요청을 보내기 위해 client를 생성했던 것을 기억하나요? 기억나지 않아도 괜찮습니다. 우리는 아래의 코드를 통해 트위터 봇의 행동을 지시할 client(=계정)를 생성했습니다.

 #  client object 만들기 = 트위터 api와 소통할 수 있는 "object(=계정)" 만들기
    client = tweepy.API(auth, wait_on_rate_limit=True,
        wait_on_rate_limit_notify=True)

이 계정을 만들기 위해 tweepy 라는 라이브러리(=프로그래밍도구)를 사용했고, 봇이 받은 멘션을 불러올 때도 마찬가지로 이 라이브러리를 사용할 것입니다. 봇이 받은 멘션을 불러오는 코드는 매우 간단합니다. 다음의 한 줄이 그 코드 입니다.

tweepy.Cursor(api.mentions_timeline, since_id=since_id).items()

이 코드의 내용을 해석하면 아래와 같습니다. "나는 내가 가진 계정(api)으로 타임라인에 있는 나에게 보내진 멘션(=mention_timeline)을 받을 것인데, 모든 멘션이 아니라 특정 멘션 이후(=since_id)에 생성된 멘션들을 받겠다."

그리고 우리는 봇이 이미 답한 멘션에 두번 답하기를 바라지 않기 때문에 여기서 특정 멘션은 봇이 마지막으로 답변한 멘션의 아이디가 될 것입니다.

그렇다면 tweepy.Cursor는 무엇을 의미하나요? Cursor는 마우스 커서의 그 커서가 맞습니다.

일단 멘션들을 목록으로 쭉 불러온 뒤에 하나하나 살펴볼 것인데, 어디까지 봤는지를 마우스 커서로 표시하듯 Cursor로 추적해주겠단 뜻입니다.
(이에 대해 더 자세히 알고 싶다면 Iterator를 공부해보세요!)

간단히 말하면 iterator 라는 것은 목록을 순차적으로 불러주는 일회용 정수기컵통 같은 것이라고 할 수 있습니다.

하나를 뽑으면 다음것이 나오고 이미 나온 것은 통에서 사라지죠. iterator는 이 정수기컵을 하나씩 뽑아내면서 거기에 써있는 서로 다른 정보들을 읽어주는 도구라고 생각하시면 됩니다.

그런데 그 자체로는 의미가 없잖아요? 사람이 직접 컵을 하나씩 뽑아내야하듯 iterator도 자료들을 뽑아주는 도구가 필요합니다. 이때 사용하는 도구가 for 구문입니다.

for tweet in tweepy.Cursor(api.mentions_timeline, since_id=since_id).items():

멘션 리스트들을 돌면서 아래의 동일한 행동을 수행할 건데, 각각의 멘션은 일단 tweet이라고 부를게. 라는 의미 정도입니다.

요약:

  • twitter client (api)를 통해 mentions_timeline을 불러온다.
  • 멘션에 중복 답변하지 않도록 since_id를 지정한다.
  • 불러온 list를 for 명령어를 통해 차례차례 불러준다.

여기까지 하면 멘션 불러오기는 모두 끝이 났습니다. 이제 두번째로 불러온 멘션에서 키워드를 찾아봅시다.

2. 받은 멘션으로부터 키워드를 감지하기

받은 멘션으로부터 키워드를 감지는 어떻게 할까요? 간단합니다. 멘션으로 받은 트윗에 지정해둔 키워드가 있는지를 확인하는 코드를 짜면 됩니다. 그리고 파이썬에서는 매우 고맙게도 하나의 문장에 특정 단어가 포함되어있는지를 확인해주는 문법이 있습니다. 이 문법은 아래와 같습니다.

keyword = "[사냥]"
keyword in tweet.text.lower()

이 코드는 트위터의 텍스트에 키워드인 [사냥] 이라는 단어가 포함이 되어있을 경우 '참'을 선언합니다.

그리고 우리가 궁극적으로 하려는 것은 유저가 키워드 목록에 포함된 키워드 중 어떤 키워드를 가지고 있는지를 확인하는 것입니다.

이를 구현하기 위한 절차는 아래와 같습니다.
1. keyword 목록에서 keyword를 하나씩 가져와 유저의 멘션에 포함되어있는지 확인한다.
2. 유저의 멘션에 keyword가 있으면 시행할 명령을 해당 keyword 로 지정한다.

1번은 위에서 했던 것과 마찬가지로 for 문을 통해 구현할 것이고, 2번은 위에서 소개한 문법과 if 조건문을 조합할 것입니다.

if 조건문은 if 다음에 나오는 문장이 참이면 : 아래의 문장을 실행하고 아니면 아무것도 하지 않습니다.

우리는 트윗이 키워드를 포함하면 명령어를 keyword로 지정할 것이므로, 위의 이야기를 조합하면 아래의 코드가 나옵니다.

task_name = ""
for keyword in keywords:
    if keyword in tweet.text.lower():
         task_name = keyword

요약

  • src/main.py 의 keywords에서 명령어 목록을 설정한다.
  • 이렇게 설정한 명령어의 목록과 유저가 보낸 트윗을 비교한다.
  • 유저의 트윗에 명령어가 포함되어있으면 시행할 명령에 keyword를 넘겨준다.

3. 키워드에 따른 결과물 출력하여 내보내기

키워드 분리까지 마쳤다면 다음으로는 키워드에 따른 결과물을 출력할 차례입니다. 하지만 이 부분에 대한 이야기는 길어질 예정이니 다음 게시물에서 자세히 설명하겠습니다.

profile
당신의 친절한 오타쿠

0개의 댓글