Posts 디스코드 봇(옵지 봇) 명령어 추가하기
Post
Cancel

디스코드 봇(옵지 봇) 명령어 추가하기


디스코드 봇(옵지 봇) 명령어 추가하기

개요

기존 바라미 디스코드 방에는 설광수 선배가 만든 옵지봇이 있었다. 여기엔 리그오브레전드 플레이어의 최근 승률과 가장 많이 사용한 챔피언을 알려주는 두 가지 기능이 있었는데, 유용한 명령어 몇 가지를 추가하면 더 재미있게 쓸 수 있을 것 같아 작품을 시작하게 되었다. 코드는 Python3로 작성하였고 beautifulsoup4 패키지로 전적검색 사이트의 데이터를 파싱하여 명령어에 따른 정보를 출력하는 형태로 만들었다.

옵지 봇 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import nest_asyncio
import aiohttp
import requests
import discord
from bs4 import BeautifulSoup
from discord.ext import commands


nest_asyncio.apply()


bot = commands.Bot(command_prefix='옵지 ', connector=aiohttp.TCPConnector(ssl=False))
Token = '#####################################################'


@bot.event
async def on_ready():
    print('Bot connected')


# '옵지 명령어'를 치면 옵지봇이 사용 가능한 명령어를 출력 (by 조원준)
@bot.command()
async def 명령어(ctx):
    await ctx.send('옵지봇이 사용 가능한 명령어는 승률, 모스트, 칼바람, 팀운 입니다')


# '옵지 승률 '닉넴''을 치면 '닉넴'의 승률을 출력 (by 광수선배)
@bot.command()
async def 승률(ctx, arg):
    response = requests.get('https://www.op.gg/summoner/userName={}'.format(arg), headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'})
    soup = BeautifulSoup(response.content, 'html.parser')
    table = soup.find('table', {'class': 'GameAverageStats'})

    WL = table.tr.td.div.find_all('span')

    win = WL[1].text
    lose = WL[2].text
    win_lose = str(int(win) + int(lose))
    winning_rate = table.find_all('tr')[1].td.div.find_all('div')[1].text

    await ctx.send('{}의 최근 {}판 승률은 {}입니다'.format(arg, win_lose, winning_rate))


# '옵지 모스트 '닉넴''을 치면 이번시즌 '닉넴'의 모스트 챔프를 출력 (by 광수선배)
@bot.command()
async def 모스트(ctx, arg):
    response = requests.get('https://www.op.gg/summoner/userName={}'.format(arg), headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'})

    soup = BeautifulSoup(response.content,'html.parser')

    most = soup.select(".MostChampionContent .ChampionName > a")
    most1 = most[0].get_text().strip()

    await ctx.send('이번시즌 {}의 모스트는 {}입니다'.format(arg, most1))


# '옵지 칼바람 '닉넴''을 치면 '닉넴'의 칼바람 전적과 승률을 출력 (by 조원준)
@bot.command()
async def 칼바람(ctx, arg):
    response = requests.get('https://poro.gg/summoner/kr/{}'.format(arg))
    soup = BeautifulSoup(response.content,'html.parser')
    table = soup.find('div',{'class':'col-12 col-lg-2 mt-2 mt-lg-0 order-2 order-lg-3'})

    WL_HA = table.div.div.find_all('div')[1].find_all('div')[1].text.strip().split()
    winning_rate_HA = table.div.div.find_all('div')[1].div.b.text
    await ctx.send('{}의 칼바람 전적은 {}, 승률 {}입니다'.format(arg, WL_HA[0]+" "+WL_HA[1], winning_rate_HA))


# '옵지 팀운 '닉넴''을 치면 '닉넴'의 팀운을 출력 (by 조원준)
@bot.command()
async def 팀운(ctx, arg):
    response = requests.get('https://your.gg/kr/profile/{}'.format(arg))
    soup = BeautifulSoup(response.content,'html.parser')
    table = soup.find('div',{'class':'d-flex justify-content-between align-items-center w-100'})

    TLdictionary = {'S':'최고','A':'좋음','B':'보통','C':'나쁨','D':'극악'}
    teamluck1 = table.select_one("div:nth-child(1) > div > div > div > div > div:nth-child(3) > div.d-flex.justify-content-center.align-items-center.gg-important-number").find('a').text.strip()
    if teamluck1 in TLdictionary : TL = TLdictionary[teamluck1]
    teamluck2 = soup.select_one("div:nth-child(1) > div > div > div > div > div:nth-child(3) > div.d-flex.flex-column.align-items-center.gg-sub-description.mt-3").find_all('span')[3].text.strip().split()
    await ctx.send('{}의 팀운은 {}, 상위{}입니다'.format(arg, TL, teamluck2[1]))


# '옵지 나가'를 치면 logout함
@bot.command()
async def 나가(ctx):
    await ctx.send('잘있어요')
    await ctx.bot.change_presence(status=discord.Status.offline)
    await ctx.bot.logout()
    print("Bot disconnected")


bot.run(Token)

옵지 봇 사용법

현재 바라미 디스코드에서 돌아가고 있는 봇은 본인의 Google Cloud Platform(GCP) VM 인스턴스를 사용해서 계속 실행하고 있으니 채팅 채널에서 명령어만 입력하면 사용 가능하다.
하지만 혹시 다른 서버에서 옵지 봇의 기능을 사용하고 싶은 경우 다음을 따르면 된다.

  1. 사용자가 자신의 봇을 생성하여 원하는 디스코드 서버에 초대한 후 위 코드의 Token = ‘ ‘ 자리에 자신의 봇 Token을 넣고 실행한다.
  2. 초대한 서버의 디스코드 채팅 채널에 “옵지 ‘명령어’ ‘닉네임’“을 입력하면 본인의 봇이 명령어에 맞는 결과를 출력해서 알려준다.

실행 예시 :

문제점 및 개선방안

  • 코드가 전적 검색 사이트의 HTML을 긁어온 후 원하는 데이터를 찾는 방식인데, 대부분 HTML에서 데이터의 selector를 그대로 복사해서 사용했기 때문에 코드의 가독성이 매우 좋지 않다.
  • 데이터를 가져올 전적검색 사이트에서 전적 갱신이 이뤄지지 않으면 원하는 데이터를 얻을 수 없기 때문에 전적검색 사이트에 들어가 직접 갱신해줘야 하는데, 현재 옵지 봇에서 사용하는 전적검색 사이트가 OP.GG, YOUR.GG, PORO.GG 세 개나 되어 수동 갱신작업이 매우 번거롭다.
    이를 해결하기 위해 Python Selenium을 이용하여 봇에 전적갱신 명령어를 추가하려 했으나 아직은 Python Selenium을 이해하기 어려워 완성하지 못하였다.
  • 전적검색 사이트의 변화에 취약하다. 실제로 이전에는 정상적으로 작동하던 명령어가 최근에 작품을 제출하려고 다시 시도해보니 갑자기 실행이 안되는 경우가 있었는데, 확인해보니 403에러가 났던 것으로 User-Agent를 변경하여 해결했지만 이처럼 사이트의 변화에 갑자기 작동하지 않을 수 있다는 문제점이 있다.
    만일 전적검색 사이트의 변화와 상관없이 지속적으로 사용할 봇을 만들고 싶다면 Riot api를 직접 가져오는 방식으로 만들면 좋을 것 같다. (하지만 그러면 더이상 “옵지” 봇이 아니게 되므로 본인은 그렇게 하지 않을 것이다.)
  • 봇의 명령어 제작 단계에서 테스트를 본인의 리그오브레전드 계정으로만 진행하다 보니 특수한 경우에서 어떻게 출력할 수 있을지를 고려하지 못한 부분이 많다.
    가령 이번시즌 랭크 플레이 전적이 없으면 모스트 명령어를 사용했을 때 옵지 봇은 아무것도 출력하지 못하는데, 이와 관련하여 ‘{}은 이번시즌 랭크 전적이 없습니다.’를 출력하도록 명령어를 추가하면 좋을 것 같다.
This post is licensed under CC BY 4.0 by the author.

i18n-language.js - Simple i18n language with Vanilla JS

Beacon을 이용한 위치추적과 자율주행 자동차