Python으로 디스코드(Discord) 봇 만들기

    우리팀은 대화를 회사 메신저를 활용하지 않고 디스코드를 사용하고 있다보니 디스코드에 흥미를 느끼게 되었고 디스코드로 뭔가 제품을 시연하는 것이 상당히 편리하다는 것을 깨닫게 되었다. 별도의 데모 페이지를 구축하는 것보다 디스코드 봇을 만들어서 시연을 하게 되면 업무의 능률도 빠르고 필자처럼 back-end api를 만드는 사람에게 상당히 유용해 보인다.

     

    디스코드는 다양한 언어를 제공해주지만 라이트하게 가기 위해서 파이썬으로 진행하려 한다. 처음에는 자바로 진행하려 했지만 목업 수준을 만들기 위해서 자바로 하는 것만큼 바보 같은 것이 없기 때문에 우선 Python으로 한 후 막히는 부분이 있으면 그때 자바를 고려할 예정이다.

     

    라이브러리 설치

    D:\Project\bots\discord>pip install discord
    Collecting discord
      Downloading discord-1.0.1-py3-none-any.whl (1.1 kB)
    Collecting discord.py>=1.0.1
      Downloading discord.py-1.5.1-py3-none-any.whl (701 kB)
         |████████████████████████████████| 701 kB 1.3 MB/s
    Collecting aiohttp<3.7.0,>=3.6.0
      Downloading aiohttp-3.6.3.tar.gz (1.1 MB)
         |████████████████████████████████| 1.1 MB ...
      Installing build dependencies ... done
      Getting requirements to build wheel ... done
        Preparing wheel metadata ... done
    Collecting async-timeout<4.0,>=3.0
      Downloading async_timeout-3.0.1-py3-none-any.whl (8.2 kB)
    Collecting multidict<5.0,>=4.5
      Downloading multidict-4.7.6-cp38-cp38-win_amd64.whl (48 kB)
         |████████████████████████████████| 48 kB ...
    Requirement already satisfied: chardet<4.0,>=2.0 in d:\anaconda3\lib\site-packages (from aiohttp<3.7.0,>=3.6.0->discord.py>=1.0.1->discord) (3.0.4)
    Requirement already satisfied: attrs>=17.3.0 in d:\anaconda3\lib\site-packages (from aiohttp<3.7.0,>=3.6.0->discord.py>=1.0.1->discord) (19.3.0)
    Collecting yarl<1.6.0,>=1.0
      Downloading yarl-1.5.1-cp38-cp38-win_amd64.whl (128 kB)
         |████████████████████████████████| 128 kB 6.8 MB/s
    Requirement already satisfied: idna>=2.0 in d:\anaconda3\lib\site-packages (from yarl<1.6.0,>=1.0->aiohttp<3.7.0,>=3.6.0->discord.py>=1.0.1->discord) (2.10)
    Building wheels for collected packages: aiohttp
      Building wheel for aiohttp (PEP 517) ... done
      Created wheel for aiohttp: filename=aiohttp-3.6.3-py3-none-any.whl size=440473 sha256=944b05addbf24892b58c0e5f6a71097ffc7819d613d105c3e329b1d5940cdd93
      Stored in directory: c:\users\user\appdata\local\pip\cache\wheels\2d\6d\bb\486f8c893f1dcc917860a5b3e2f2ca286c398f7d548ffc649c
    Successfully built aiohttp
    Installing collected packages: async-timeout, multidict, yarl, aiohttp, discord.py, discord
    Successfully installed aiohttp-3.6.3 async-timeout-3.0.1 discord-1.0.1 discord.py-1.5.1 multidict-4.7.6 yarl-1.5.1
    

    pip install discord로 discord 라이브러리를 설치 한다.

     

    디스코드에서 봇 생성

    discord.com

    discord 홈페이지에서 아래(footer)로 스크롤을 내리면 위와 같은 화면이 나오게 된다. 여기에 개발자라고 적혀 있는 메뉴를 클릭한다.

     

    자비스라는 봇을 생성한 필자

    개발자에 들어간 후 좌측 메뉴가 여러개 있는데 Application을 선택 한 후 New Application으로 내가 원하는 어플리케이션을 새로 생성한다.

     

    봇을 추가하는 상황

    어플리케이션을 들어간 후, 좌측에 메뉴를 보면 Bot이라는 메뉴가 존재하는데 여기에 봇을 생성한 후 토큰값을 다른 곳에 복사한다. 봇을 생성하였다면, 어플리케이션의 client 아이디를 복사한 후 아래의 url을 실행한다.

     

    봇을 대화서버에 추가

    https://discord.com/oauth2/authorize?client_id={클라이언트id}&permissions=8&scope=bot

    위 url의 클라이언트id에 어플리케이션 클라이언트 id를 삽입 한 후, 채널에 봇이 생성된 것을 확인한다.

     

     

    파이썬코드

    import discord
    from discord.ext import commands
    
    app = commands.Bot(command_prefix='!')
    
    @app.event
    async def on_ready():
        print(app.user.name, 'has connected to Discord!')
        await app.change_presence(status=discord.Status.online, activity=None)
        print("ready")
    
    
    @app.command()
    async def 자비스(ctx, *, text):
        await ctx.send(text)
    
    
    app.run('토큰값을 여기에 입력')

    맨 아래 토큰값을 입력하는 곳에 본인의 token값을 넣고 위 python을 실행을 하면 

     

    자비스 has connected to Discord!
    ready

    봇이 위와 같은 메세지를 콘솔에 띄우며 연결이 된다. 위 코드를 잠시 설명을 하자면, 처음 실행을 하면, on_ready()를 실행해서 on_ready 메소드 아래 내용들을 실행하게 되고...

     

    다음 대화를 할 때, !자비스후 내용을 입력하게 되면 해당 내용을 내 봇이 그대로 따라하는 코드이다.

     

    봇을 테스트해본 결과

    이와같이 매우 쉽게 디스코드 봇을 만들 수 있다. @app.command()는 controller 역할을 하게 되고, 해당 메소드에 들어간 내용을 분석하여 챗봇을 호출한다던지 아니면 어떤 api 서비스를 호출하는 기능들을 넣을 수 있을 것이다.

     

    그러나 위 코드를 그대로 실행을 할 때 아래부분과 같이 !자비스를 한 이후 아무런 메세지를 전달하지 않으면 에러가 떨어진다. 

    Ignoring exception in command 자비스:
    Traceback (most recent call last):
      File "C:\Users\user\anaconda3\lib\site-packages\discord\ext\commands\bot.py", line 903, in invoke
        await ctx.command.invoke(ctx)
      File "C:\Users\user\anaconda3\lib\site-packages\discord\ext\commands\core.py", line 851, in invoke
        await self.prepare(ctx)
      File "C:\Users\user\anaconda3\lib\site-packages\discord\ext\commands\core.py", line 786, in prepare
        await self._parse_arguments(ctx)
      File "C:\Users\user\anaconda3\lib\site-packages\discord\ext\commands\core.py", line 706, in _parse_arguments
        kwargs[name] = await self.transform(ctx, param)
      File "C:\Users\user\anaconda3\lib\site-packages\discord\ext\commands\core.py", line 542, in transform
        raise MissingRequiredArgument(param)
    discord.ext.commands.errors.MissingRequiredArgument: text is a required argument that is missing.

     

    이럴 경우 아래와 같이 Null 처리를 넣어주면 된다.

    @app.command()
    async def 자비스(ctx, *, text = None):
        if(text != None):
            await ctx.send(text)

     

    참고자료

    https://discord.com/developers/docs/intro

    댓글

    Designed by JB FACTORY