4.파이썬을 이용한 디스코드 봇 만들기: 리그 오브 레전드 API (2)

3 분 소요

디스코드 봇으로 리그 오브 레전드 API 데이터 출력

안녕하세요. 이전 글에 이어서 작성하겠습니다.
리그 오브 레전드 API를 편하게 Riot API로 부르겠습니다.

1. 실시간 매치 데이터 인덱싱

  • SPECTATOR-V4 API 코드
import requests

token = '(자신의 개발용 API 키)'
name = 'Hide on bush'
url = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/"+name

response = requests.get(url, headers={"X-Riot-Token": token})
suid = response.json()["id"] # encryptedSummonerId

url = "https://kr.api.riotgames.com/lol/spectator/v4/active-games/by-summoner/"+suid

response = requests.get(url, headers={"X-Riot-Token": token})
print("status_code: {}".format(response.status_code))
print(response.json())

그럼 저희가 처음에 만들었던 디스코드 봇 파일에 실시간 매치 데이터를 가져오는 SPECTATOR-V4 API 코드를 넣어 응용해보겠습니다.

import discord, os, requests
from discord.ext import commands

riot_api_token = "(자신의 개발용 API 키)"

    ...생략...

@bot.command()
async def 게임(ctx, *args):

    name = " ".join(args)  # 띄어쓰기가 포함된 소환사 명 처리

    url = "https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/" + name

    response = requests.get(url, headers={"X-Riot-Token": riot_api_token})
    suid = response.json()["id"]  # encryptedSummonerId

    url = ("https://kr.api.riotgames.com/lol/spectator/v4/active-games/by-summoner/" + suid)

    response = requests.get(url, headers={"X-Riot-Token": riot_api_token})
    print("status_code: {}".format(response.status_code))

    participants = []
    for row in response.json()["participants"]:
        participants_row = {}
        participants_row["championId"] = row["championId"]
        participants_row["summonerName"] = row["summonerName"]
        participants.append(participants_row)

    out = "챔피언 | 소환사 명\n"
    for data in participants:
        out += "{} | {}\n".format(data["championId"], data["summonerName"])
    await ctx.send(out)
  • 실행 결과

d1

JSON파일의 구조를 파악하시면 API 요청으로 전달 받은 데이터를 쉽게 응용할 수 있습니다. 파이썬에서 딕셔너리 형태로 JSON파일 인덱싱이 가능하다는 점 때문에 코드를 더욱 간결하게 표현이 가능합니다.

2. 챔피언, 소환사 주문 이름 데이터 불러오기

실시간 매치 데이터를 불러오는데는 성공했지만 아직 끝나지 않았습니다. 챔피언 혹은 소환사 주문의 데이터 값이 Integer형태의 ID 값으로 표현되네요. 따라서 해당 ID값이 무엇을 의미하는지 알아낼 필요가 있습니다!

Riot API Docs에 가시면 해당 내용에 대한 설명과 함께 모든 챔피언의 데이터가 들어있는 JSON파일을 제공합니다. 이 데이터를 이용해봅시다.

모든 리그 오브 레전드의 게임 데이터와 에셋들을 포함한 것을 Data Dragon이라고 합니다. 게임이 업데이트 될때 마다 해당 데이터가 변경 될 수 있다는 의미입니다.

d2

먼저 홈페이지에서 제공하는 JSON파일 주소의 구조를 확인해봅시다.

... /cdn/11.4.1/data/en_US/champion.json

11.4.1은 DataDragon의 버전이고 en_US은 데이터의 언어, champion.json은 데이터를 의미하겠네요. 저희는 해당 버전의 한글로 된 챔피언 데이터를 가져와서 이용해보겠습니다.

    ...생략...

static_champ_list = requests.get(
    "http://ddragon.leagueoflegends.com/cdn/11.4.1/data/ko_KR/champion.json"
).json()
champ_dict = {}
# 모든 챔피언의 ID에 대치되는 이름을 champ_dict에 저장
for champ in static_champ_list["data"]:
    row = static_champ_list["data"][champ]
    champ_dict[row["key"]] = row["name"]

# 이번 매치에서의 각각의 소환사 챔피언의 ID를 이름으로 변경
for row in participants:
    row["championId"] = champ_dict[str(row["championId"])]

out = "챔피언 | 소환사 명\n"
for data in participants:
    out += "{} | {}\n".format(data["championId"], data["summonerName"])
await ctx.send(out)
  • 실행 결과

d3

성공적으로 챔피언 이름을 불러왔습니다! 각각의 소환사 주문도 똑같은 방법을 이용하여 데이터를 이용할 수 있습니다. 또한 앞서 작성된 글의 내용과 함께 응용하여 소환사의 랭크 티어 현황, 이번 시즌의 승리, 패배 횟수 데이터까지 받아올 수 있습니다. 자세한 내용은 Riot API에서 제공하는 각각의 API들을 한번씩 사용해보시는 것을 추천드립니다.

3. discord.py의 @tasks.loop

마지막으로, 디스코드 봇의 강력한 기능인 @tasks.loop에 대해 알아보겠습니다.

봇이 개발하는 이유가 무엇일까 하고 생각해본다면 어떤 작업에 대한 수행을 자동으로 해준다는 점에 의미가 있다고 생각합니다. 따라서 저희가 개발하는 봇은 사용자와의 상호작용은 확실하게 구현이 가능하나, 자동화에 대해선 discord.py에서 제공하는 Event Reference을 제외하고는 이벤트를 개발자의 입맛에 맞게 수정하기는 힘든 부분이 있습니다.

이때 discord.py에서는 discord.ext.tasks.Loop 클래스를 통하여 봇의 행동을 반복시키는 것이 가능합니다! 코드와 함께 해당 기능을 설명하겠습니다.

from discord.ext import commands, tasks #discord.ext.tasks 필요

    ...생략...

@bot.command()
async def 시작(ctx):
    loop_task.start()
    return

@tasks.loop(seconds=10.0)
async def loop_task():
    for guild in bot.guilds:
        await guild.system_channel.send('모든 채널에 알림!')

@tasks.loop 으로 해당 async 함수가 반복됨을 명시합니다. 또한 매개변수로 반복 주기를 설정할 수 있습니다. 예) seconds(float), minutes(float), hours(float), reconnect(bool)

해당 코드 처럼 설정한 @tasks.loop는 해당 함수를 호출하여 반복을 시작, 중단, 재시작이 가능합니다. 예) *.start(), *.stop(), *.restart()

부록.

1. 에러 처리

  • 소환사를 불러오는 도중 오류 발생

discord.ext.commands.errors.CommandInvokeError: Command raised an exception: KeyError: ‘participants’

Riot API를 사용하여 작성한 코드를 실행하다보면 코드에는 아무런 문제가 없음에도 불구하고 예상치 못한 오류들이 발생하기도 합니다. 그 이유는 HTTP 통신이 항상 같은 값을 전달하는 것이 아니기 때문입니다.

d4

저희가 사용하는 Riot API에서 받을 수 있는 모든 HTTP 상태 코드는 사진과 같습니다. HTTP 통신에서는 요청에 따른 상태 코드를 데이터로 함께 받습니다. 따라서 발생할 수 있는 모든 상태에 대한 예외 처리를 해준다면 예상치 못한 오류를 방지할 수 있을겁니다. 또한 이번에 작성한 코드 뿐만 아니라 어떤 코드를 작성할때도 항상 가장 중요한것은 예외 처리라고 생각합니다.

댓글남기기