Comment faire un bot discord en Python – Real Python

By | août 19, 2019

Cours Python en ligne

Dans un monde où les jeux vidéo sont si importants pour beaucoup de gens, la communication et la communauté autour des jeux sont essentielles. Discord offre à la fois ces solutions et bien d’autres dans un ensemble bien conçu. Dans ce didacticiel, vous apprendrez à créer un bot Discord en Python afin de tirer le meilleur parti de cette fantastique plate-forme.

À la fin de cet article, vous apprendrez:

  • Qu'est-ce que la discorde et pourquoi est-il si précieux?
  • Comment créer un bot Discord via le portail de développeur
  • Comment créer des connexions Discord
  • Comment gérer les événements
  • Comment accepter les commandes et valider les hypothèses
  • Comment interagir avec différentes API Discord

Vous commencerez par apprendre ce qu'est Discord et pourquoi il est précieux.

Qu'est-ce que la discorde?

Discord est une plate-forme de communication vocale et textuelle pour les joueurs.

Les joueurs, les banderoles et les développeurs utilisent Discord pour discuter de jeux, répondre à des questions, dialoguer pendant qu'ils jouent, et bien plus encore. Il a même un magasin de jeux, avec des critiques et un service d'abonnement. C'est presque un guichet unique pour les communautés de joueurs.

Bien que vous puissiez construire de nombreuses choses à l’aide des API Discord, ce tutoriel se concentrera sur un résultat d’apprentissage particulier: comment créer un bot Discord en Python.

Qu'est-ce qu'un bot?

La discorde gagne en popularité. En tant que tels, des processus automatisés, tels que l'interdiction d'utilisateurs inappropriés et la réaction à leurs demandes, sont essentiels au développement et à la croissance d'une communauté.

Les programmes automatisés qui ressemblent à des utilisateurs et réagissent automatiquement aux événements et aux commandes sur Discord sont appelés utilisateurs de bot. Discord bot utilisateurs (ou simplement bots) ont des applications presque illimitées.

Par exemple, disons que vous gérez une nouvelle guilde Discord et qu’un utilisateur s’associe pour la première fois. Excité, vous pouvez personnellement contacter cet utilisateur et lui souhaiter la bienvenue dans votre communauté. Vous pouvez également leur parler de vos chaînes ou leur demander de se présenter.

L’utilisateur se sent accueilli et apprécie les discussions qui se déroulent dans votre guilde et, à son tour, invite des amis.

Au fil du temps, votre communauté a tellement grandi qu’il n’est plus possible de contacter personnellement chaque nouveau membre, mais vous souhaitez tout de même lui envoyer quelque chose pour le reconnaître en tant que nouveau membre de la guilde.

Avec un bot, il est possible de réagir automatiquement au nouveau membre rejoignant votre guilde. Vous pouvez même personnaliser son comportement en fonction du contexte et contrôler la manière dont il interagit avec chaque nouvel utilisateur.

C’est formidable, mais ce n’est qu’un petit exemple de l’utilité d’un bot. Il y a tellement d'opportunités pour vous de faire preuve de créativité avec les robots, une fois que vous savez comment les fabriquer.

Il existe deux étapes clés lors de la création d’un bot:

  1. Créez l'utilisateur de bot sur Discord et enregistrez-le auprès d'une guilde.
  2. Écrivez un code qui utilise les API de Discord et implémente les comportements de votre bot.

Dans la section suivante, vous apprendrez à créer un bot Discord dans le portail des développeurs Discord.

Comment créer un bot discord dans le portail des développeurs

Avant de pouvoir plonger dans un code Python pour gérer des événements et créer des automatisations intéressantes, vous devez d'abord créer quelques composants Discord:

  1. Un compte
  2. Une application
  3. Un bot
  4. Une guilde

Vous en apprendrez plus sur chaque pièce dans les sections suivantes.

Une fois que vous avez créé tous ces composants, vous les lierez en enregistrant votre bot avec votre guilde.

Vous pouvez commencer en vous rendant sur le portail des développeurs Discord.

Création d'un compte Discord

La première chose que vous verrez est une page de destination sur laquelle vous devrez vous connecter, si vous avez un compte existant, ou créer un nouveau compte:

Discord: écran de connexion au compte

Si vous devez créer un nouveau compte, cliquez sur le bouton registre bouton ci-dessous S'identifier et entrez les informations de votre compte.

Une fois que vous avez terminé, vous serez redirigé vers la page d'accueil du portail de développeur, où vous créerez votre application.

Créer une application

Un application vous permet d’interagir avec les API de Discord en fournissant des jetons d’authentification, des autorisations, etc.

Pour créer une nouvelle application, sélectionnez Nouvelle application:

Écran Discord: Mes applications

Ensuite, vous serez invité à nommer votre application. Sélectionnez un nom et cliquez Créer:

Discord: nommer une application

Toutes nos félicitations! Vous avez fait une demande Discord. Sur l'écran résultant, vous pouvez voir des informations sur votre application:

Discord: Information générale sur l'application

N'oubliez pas que tout programme qui interagit avec les API Discord nécessite une application Discord, pas seulement des bots. Les API liées aux robots ne sont qu’un sous-ensemble de l’interface totale de Discord.

Cependant, puisque ce tutoriel explique comment créer un bot Discord, accédez à la Bot onglet dans la liste de navigation de gauche.

Créer un bot

Comme vous l'avez appris dans les sections précédentes, un utilisateur de bot est un utilisateur qui écoute et réagit automatiquement à certains événements et à certaines commandes sur Discord.

Pour que votre code soit réellement manifesté sur Discord, vous devez créer un utilisateur bot. Pour ce faire, sélectionnez Ajouter un bot:

Discord: Ajouter Bot

Une fois que vous confirmez que vous souhaitez ajouter le bot à votre application, vous verrez le nouvel utilisateur du bot sur le portail:

Discord: Bot créé avec succès

Notez que, par défaut, votre utilisateur de bot héritera du nom de votre application. Au lieu de cela, mettez à jour le nom d'utilisateur avec quelque chose de plus similaire à bot, tel que RealPythonTutorialBot, et Sauvegarder les modifications:

Discord: Renommer Bot

Maintenant, le bot est prêt et prêt à partir, mais vers où?

Un utilisateur de bot n’est pas utile s’il n’interagit pas avec d’autres utilisateurs. Ensuite, vous créerez une guilde afin que votre bot puisse interagir avec d’autres utilisateurs.

Créer une guilde

UNE guilde (ou un serveur, comme on l’appelle souvent dans l’interface utilisateur de Discord), est un groupe spécifique de canaux où les utilisateurs se rassemblent pour discuter.

Par exemple, imaginons que vous souhaitiez créer un espace où les utilisateurs peuvent se réunir et parler de votre dernier jeu. Vous commenceriez par créer une guilde. Ensuite, dans votre guilde, vous pourriez avoir plusieurs canaux, tels que:

  • Discussion générale: Un canal permettant aux utilisateurs de parler de tout ce qu'ils veulent
  • Spoilers, Attention: Un canal pour les utilisateurs qui ont fini votre jeu pour parler de tout ce que le jeu final révèle
  • Annonces: Un canal pour annoncer les mises à jour du jeu et les utilisateurs pour en discuter

Une fois que vous avez créé votre guilde, vous invitez d’autres utilisateurs à la renseigner.

Pour créer une guilde, rendez-vous sur votre page d'accueil Discord:

Discord: page d'accueil du compte utilisateur

Depuis cette page d'accueil, vous pouvez afficher et ajouter des amis, des messages directs et des guildes. De là, sélectionnez le + icône sur le côté gauche de la page Web pour Ajouter un serveur:

Discord: Ajouter un serveur

Cela présentera deux options, Créer un serveur et Rejoindre un serveur. Dans ce cas, sélectionnez Créer un serveur et entrez un nom pour votre guilde:

Discord: nommer un serveur

Une fois que vous avez fini de créer votre guilde, vous pourrez voir les utilisateurs à droite et les canaux à gauche:

Discord: Serveur nouvellement créé

La dernière étape de Discord consiste à enregistrer votre bot auprès de votre nouvelle guilde.

Ajouter un bot à une guilde

Un bot ne peut pas accepter d'invitations comme un utilisateur normal. Au lieu de cela, vous ajouterez votre bot en utilisant le protocole OAuth2.

Pour ce faire, revenez sur le portail de développeur et sélectionnez la page OAuth2 dans la navigation de gauche:

Discord: Application OAuth2

Dans cette fenêtre, vous verrez le générateur d’URL OAuth2.

Cet outil génère une URL d'autorisation qui atteint l'API OAuth2 de Discord et autorise l'accès à l'API à l'aide des informations d'identification de votre application.

Dans ce cas, vous souhaiterez accorder l’accès de l’utilisateur de votre application aux API Discord à l’aide des informations d’identification OAuth2 de votre application.

Pour ce faire, faites défiler et sélectionnez bot du SCOPES options et Administrateur de BOT PERMISSIONS:

Discord: domaines d'application et autorisations d'accès au bot

Maintenant, Discord a généré l’URL d’autorisation de votre application avec la portée et les autorisations sélectionnées.

Sélectionner Copie à côté de l'URL générée pour vous, collez-la dans votre navigateur et sélectionnez votre guilde dans les options du menu déroulant:

Discord: Ajouter Bot à un serveur

Cliquez sur Autoriser, et tu as fini!

Si vous retournez dans votre guilde, vous verrez que le bot a été ajouté:

Discord: Bot ajouté à la guilde

En résumé, vous avez créé:

  • Un application que votre bot utilisera pour s’authentifier avec les API de Discord
  • UNE bot utilisateur que vous utiliserez pour interagir avec d'autres utilisateurs et événements de votre guilde
  • UNE guilde dans lequel votre compte d'utilisateur et votre utilisateur de bot seront actifs
  • UNE Discorde compte avec lequel vous avez créé tout le reste et que vous utiliserez pour interagir avec votre bot

Vous savez maintenant comment créer un bot Discord à l'aide du portail de développeur. Vient ensuite le truc amusant: implémenter votre bot en Python!

Comment faire un bot discord en Python

Puisque vous apprenez à créer un bot Discord avec Python, vous utiliserez discord.py.

discord.py est une bibliothèque Python qui implémente de manière exhaustive les API de Discord de manière efficace et pythonique. Cela inclut l’utilisation de l’implémentation Async IO de Python.

Commencez par installer discord.py avec pépin:

$ pip installer -U discord.py

Maintenant que vous avez installé discord.py, vous l’utiliserez pour créer votre première connexion à Discord!

Création d'une connexion discord

La première étape de la mise en œuvre de votre utilisateur de bot consiste à créer une connexion à Discord. Avec discord.py, vous le faites en créant une instance de Client:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

client = discorde.Client()

@client.un événement
async def on_ready():
    impression(F'client.user    s'est connecté à Discord!)

client.courir(jeton)

UNE Client est un objet qui représente une connexion à Discord. UNE Client gère les événements, surveille l'état et interagit généralement avec les API Discord.

Ici, vous avez créé un Client et mis en œuvre son on_ready () gestionnaire d'événement, qui gère l'événement lorsque le Client a établi une connexion à Discord et a fini de préparer les données envoyées par Discord, telles que l'état de connexion, les données de guilde et de canal, etc.

En d'autres termes, on_ready () sera appelé (et votre message sera imprimé) une fois client est prêt pour d'autres actions. Vous en apprendrez plus sur les gestionnaires d’événements plus loin dans cet article.

Lorsque vous travaillez avec des secrets tels que le jeton Discord, il est recommandé de le lire dans votre programme à partir d’une variable d’environnement. L'utilisation de variables d'environnement vous aide à:

  • Évitez de mettre les secrets dans le contrôle de source
  • Utilisez différentes variables pour les environnements de développement et de production sans modifier votre code

Tant que vous pourriez export DISCORD_TOKEN = votre-jeton-bot, une solution plus simple consiste à économiser .env fichier sur toutes les machines qui exécuteront ce code. C’est non seulement plus facile, car vous n’aurez pas à exportation votre jeton chaque fois que vous effacez votre shell, mais cela vous empêche également de stocker vos secrets dans l’historique de votre shell.

Créer un fichier nommé .env dans le même répertoire que bot.py:

# .env
DISCORD_TOKEN = votre-jeton-bot

Vous devrez remplacer your-bot-token avec le jeton de votre bot, que vous pouvez obtenir en retournant à la Bot page sur le portail des développeurs et en cliquant sur Copie sous le JETON section:

Discord: Copier le jeton de bot

En regardant en arrière bot.py vous remarquerez une bibliothèque appelée DOTENV. Cette bibliothèque est pratique pour travailler avec .env des dossiers. load_dotenv () charge les variables d'environnement d'un .env fichier dans les variables d’environnement de votre shell afin que vous puissiez les utiliser dans votre code.

Installer DOTENV avec pépin:

$ pip installer -U python-dotenv

Finalement, client.run () exécute votre Client en utilisant le jeton de votre bot.

Maintenant que vous avez configuré les deux bot.py et .env, vous pouvez exécuter votre code:

$ bot.py python
RealPythonTutorialBot # 9643 s'est connecté à Discord!

Génial! Votre Client connecté à Discord en utilisant le jeton de votre bot. Dans la section suivante, vous allez construire sur ce Client en interagissant avec plus d'API Discord.

Interaction avec les API Discord

Utilisant un Client, vous avez accès à un large éventail d’API Discord.

Par exemple, supposons que vous vouliez écrire le nom et l’identifiant de la guilde avec laquelle vous avez enregistré votre utilisateur de bot sur la console.

Tout d’abord, vous devrez ajouter une nouvelle variable d’environnement:

# .env
DISCORD_TOKEN = votre-jeton-bot
DISCORD_GUILD = votre-nom-de-guilde

N’oubliez pas que vous devrez remplacer les deux espaces réservés par des valeurs réelles:

  1. your-bot-token
  2. votre-nom-de-guilde

Rappelez-vous que Discord appelle on_ready (), que vous avez utilisé auparavant, une fois le Client a établi la connexion et préparé les données. Donc, vous pouvez compter sur les données de guilde disponibles à l'intérieur on_ready ():

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')
GUILDE = os.getenv('DISCORD_GUILD')

client = discorde.Client()

@client.un événement
async def on_ready():
    pour guilde dans client.guildes:
        si guilde.prénom == GUILDE:
            Pause

    impression(
        F'client.user    est connecté à la guilde suivante: n'
        F'nom de guilde(id: guild.id) '
    )

client.courir(JETON)

Ici, vous avez parcouru les données de guilde que Discord a envoyées clientà savoir client.guilds. Ensuite, vous avez trouvé la guilde avec le nom correspondant et imprimé une chaîne formatée pour stdout.

Exécutez le programme pour voir les résultats:

$ bot.py python
RealPythonTutorialBot # 9643 est connecté à la guilde suivante:
RealPythonTutorialServer (id: 571759877328732195)

Génial! Vous pouvez voir le nom de votre bot, le nom de votre serveur et le numéro d’identification du serveur.

Une autre donnée intéressante que vous pouvez extraire d’une guilde est la liste des utilisateurs membres de la guilde:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')
GUILDE = os.getenv('DISCORD_GUILD')

client = discorde.Client()

@client.un événement
async def on_ready():
    pour guilde dans client.guildes:
        si guilde.prénom == GUILDE:
            Pause

    impression(
        F'client.user    est connecté à la guilde suivante: n'
        F'nom de guilde(id: guild.id) n'
    )

    membres = ' n    - '.joindre([[[[membre.prénom pour membre dans guilde.membres])
    impression(F'Membres de la guilde: n    - membres')

client.courir(JETON)

En boucle à travers membres de guilde, vous avez tiré les noms de tous les membres de la guilde et les avez imprimés avec une chaîne formatée.

Lorsque vous exécutez le programme, vous devriez au moins voir le nom du compte avec lequel vous avez créé la guilde et le nom de l'utilisateur du bot lui-même:

$ bot.py python
RealPythonTutorialBot # 9643 est connecté à la guilde suivante:
RealPythonTutorialServer (id: 571759877328732195)

Membres de la guilde:
    - aronq2
    - RealPythonTutorialBot

Ces exemples effleurent à peine la surface des API disponibles sur Discord. N'oubliez pas de consulter leur documentation pour voir tout ce qu'elles ont à offrir.

Ensuite, vous découvrirez certaines fonctions d’utilitaire et leur expliquer comment simplifier ces exemples.

Utiliser les fonctions utilitaires

Reprenons l’exemple de la dernière section où vous avez imprimé le nom et l’identifiant de la guilde du bot:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')
GUILDE = os.getenv('DISCORD_GUILD')

client = discorde.Client()

@client.un événement
async def on_ready():
    pour guilde dans client.guildes:
        si guilde.prénom == GUILDE:
            Pause

    impression(
        F'client.user    est connecté à la guilde suivante: n'
        F'nom de guilde(id: guild.id) '
    )

client.courir(JETON)

Vous pouvez nettoyer ce code en utilisant certaines des fonctions utilitaires disponibles dans discord.py.

discord.utils.find () est un utilitaire qui peut améliorer la simplicité et la lisibilité de ce code en remplaçant le pour boucle avec une fonction intuitive et abstraite:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')
GUILDE = os.getenv('DISCORD_GUILD')

client = discorde.Client()

@client.un événement
async def on_ready():
    guilde = discorde.utils.trouver(lambda g: g.prénom == GUILDE, client.guildes)
    impression(
        F'client.user    est connecté à la guilde suivante: n'
        F'nom de guilde(id: guild.id) '
    )

client.courir(JETON)

trouver() prend une fonction, appelée prédicat, qui identifie une caractéristique de l’élément dans l’itérable que vous recherchez. Ici, vous avez utilisé un type particulier de fonction anonyme, appelé lambda, comme prédicat.

Dans ce cas, vous essayez de trouver la guilde avec le même nom que celui que vous avez enregistré dans le répertoire. DISCORD_GUILD variable d'environnement. Une fois que trouver() localise un élément dans l'itérable qui satisfait le prédicat, il retournera l'élément. Ceci est essentiellement équivalent à la Pause déclaration dans l'exemple précédent, mais plus propre.

discord.py a même fait abstraction de ce concept un pas de plus avec la obtenir() utilitaire:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')
GUILDE = os.getenv('DISCORD_GUILD')

client = discorde.Client()

@client.un événement
async def on_ready():
    guilde = discorde.utils.obtenir(client.guildes, prénom=GUILDE)
    impression(
        F'client.user    est connecté à la guilde suivante: n'
        F'nom de guilde(id: guild.id) '
    )

client.courir(JETON)

obtenir() prend les arguments itérables et quelques mots clés. Les arguments de mot-clé représentent les attributs des éléments de l'itérable qui doivent tous être satisfaits pour obtenir() renvoyer l'élément.

Dans cet exemple, vous avez identifié nom = GUILD comme l'attribut qui doit être satisfait.

Maintenant que vous avez appris les bases de l’interaction avec les API, vous allez plonger un peu plus dans la fonction que vous utilisiez pour y accéder: on_ready ().

Répondre aux événements

Vous avez déjà appris que on_ready () est un événement. En fait, vous avez peut-être remarqué qu’il est identifié comme tel dans le code par le client.event décorateur.

Mais qu'est-ce qu'un événement?

Un un événement est quelque chose qui se passe sur Discord que vous pouvez utiliser pour déclencher une réaction dans votre code. Votre code écoutera et répondra aux événements.

En utilisant l’exemple que vous avez déjà vu, le on_ready () gestionnaire d'événements gère l'événement que le Client a établi une connexion avec Discord et a préparé ses données de réponse.

Alors, quand Discord déclenche un événement, discord.py acheminera les données d’événement vers le gestionnaire d’événement correspondant sur votre ordinateur connecté. Client.

Il y a deux façons de discord.py pour implémenter un gestionnaire d'événement:

  1. En utilisant le client.event décorateur
  2. Créer une sous-classe de Client et redéfinir ses méthodes de gestion

Vous avez déjà vu la mise en œuvre en utilisant le décorateur. Ensuite, regardez comment sous-classer Client:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

classe ClientClient(discorde.Client):
    async def on_ready(soi):
        impression(F'self.user    s'est connecté à Discord!)

client = ClientClient()
client.courir(jeton)

Ici comme avant, vous avez créé un client variable et appelée .courir() avec votre jeton Discord. L'actuel Client est différent, cependant. Au lieu d'utiliser la classe de base normale, client est un exemple de ClientClient, qui a un remplacement on_ready () une fonction.

Il n'y a pas de différence entre les deux styles d'implémentation des événements, mais ce tutoriel utilisera principalement la version de décorateur car il ressemble à la façon dont vous l'implémentez. Bot commandes, qui est un sujet que vous couvrirez dans un peu.

Maintenant que vous avez appris à créer un gestionnaire d’événements, passons en revue différents exemples de gestionnaires que vous pouvez créer.

Bienvenue aux nouveaux membres

Auparavant, vous avez vu l'exemple de la réponse à l'événement lorsqu'un membre rejoint une guilde. Dans cet exemple, votre utilisateur de bot pourrait leur envoyer un message, en l'accueillant dans votre communauté Discord.

Maintenant, vous allez implémenter ce comportement dans votre Client, en utilisant des gestionnaires d’événements, et vérifiez son comportement dans Discord:

# bot.py
importation os

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

client = discorde.Client()

@client.un événement
async def on_ready():
    impression(F'client.user.name    s'est connecté à Discord!)

@client.un événement
async def on_member_join(membre):
    attendre membre.create_dm()
    attendre membre.dm_channel.envoyer(
        F'Salut nom de membre, bienvenue sur mon serveur Discord! '
    )

client.courir(jeton)

Comme avant, vous avez géré le on_ready () événement en imprimant le nom de l'utilisateur du bot dans une chaîne formatée. La nouveauté est toutefois la mise en œuvre du on_member_join () gestionnaire d'événements.

on_member_join (), comme son nom l’indique, gère la venue d’un nouveau membre dans une guilde.

Dans cet exemple, vous avez utilisé member.create_dm () pour créer un canal de message direct. Ensuite, vous avez utilisé ce canal pour .envoyer() un message direct à ce nouveau membre.

Maintenant, testons le nouveau comportement de votre bot.

Tout d’abord, lancez votre nouvelle version de bot.py et attendez le on_ready () événement à déclencher, en enregistrant votre message à stdout:

$ bot.py python
RealPythonTutorialBot s'est connecté à Discord!

Maintenant, dirigez-vous sur Discord, connectez-vous et accédez à votre guilde en la sélectionnant dans la partie gauche de l'écran:

Discord: accédez au serveur

Sélectionner Inviter des gens juste à côté de la liste de guilde où vous avez sélectionné votre guilde. Cochez la case qui dit Définissez ce lien pour qu'il n'expire jamais et copier le lien:

Discord: Copier le lien d'invitation

Maintenant, avec le lien d'invitation copié, créez un nouveau compte et rejoignez la guilde en utilisant votre lien d'invitation:

Discord: Accepter l'invitation

Tout d’abord, vous verrez que Discord vous a présenté la guilde par défaut avec un message automatisé. Plus important encore, notez le badge sur le côté gauche de l'écran qui vous avertit d'un nouveau message:

Discord: Notification de message directe

Lorsque vous le sélectionnez, vous verrez un message privé de votre utilisateur de bot:

Discord: message direct

Parfait! Votre utilisateur de bot interagit maintenant avec d'autres utilisateurs avec un code minimal.

Ensuite, vous apprendrez comment répondre à des messages utilisateur spécifiques dans le chat.

Répondre aux messages

Ajoutons à la fonctionnalité précédente de votre bot en gérant les on_message () un événement.

on_message () se produit lorsqu'un message est posté dans un canal auquel votre bot a accès. Dans cet exemple, vous allez répondre au message '99! ' avec un one-line de l'émission télévisée Brooklyn Nine-Nine:

@client.un événement
async def on_message(message):
    si message.auteur == client.utilisateur:
        revenir

    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    si message.contenu == '99! ':
        réponse = au hasard.choix(brooklyn_99_quotes)
        attendre message.canal.envoyer(réponse)

La majeure partie de ce gestionnaire d'événements se penche sur les contenu du message, vérifie si elle est égale à '99! 'et répond en envoyant une citation aléatoire au canal du message, le cas échéant.

L'autre pièce est importante:

si message.auteur == client.utilisateur:
    revenir

Parce qu'un Client ne peux pas faire la différence entre un utilisateur de bot et un compte d'utilisateur normal, votre on_message () handler doit protéger contre un cas potentiellement récursif où le bot envoie un message qu’il pourrait lui-même gérer.

Pour illustrer, disons que vous voulez que votre bot écoute les utilisateurs qui se disent 'Bon anniversaire'. Vous pouvez mettre en œuvre votre on_message () gestionnaire comme ceci:

@client.un événement
async def on_message(message):
    si 'Bon anniversaire' dans message.contenu.inférieur():
        attendre message.canal.envoyer('Bon anniversaire! ')

Outre la nature potentiellement spammeuse de ce gestionnaire d'événements, il a également un effet secondaire dévastateur. Le message que le bot répond contient le même message qu’il va gérer!

Ainsi, si une personne de la chaîne annonce un «joyeux anniversaire», le bot sonne également… encore… et encore… et encore:

Discord: répétition du message de joyeux anniversaire

C’est pourquoi il est important de comparer les message.author au client.user (votre utilisateur de bot) et ignorez ses propres messages.

Alors, réparons bot.py:

# bot.py
importation os
importation au hasard

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

client = discorde.Client()

@client.un événement
async def on_ready():
    impression(F'client.user.name    s'est connecté à Discord!)

@client.un événement
async def on_member_join(membre):
    attendre membre.create_dm()
    attendre membre.dm_channel.envoyer(
        F'Salut nom de membre, bienvenue sur mon serveur Discord! '
    )

@client.un événement
async def on_message(message):
    si message.auteur == client.utilisateur:
        revenir

    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    si message.contenu == '99! ':
        réponse = au hasard.choix(brooklyn_99_quotes)
        attendre message.canal.envoyer(réponse)

client.courir(jeton)

N'oubliez pas de importer au hasard en haut du module, puisque le on_message () gestionnaire utilise random.choice ().

Exécutez le programme:

$ bot.py python
RealPythonTutorialBot s'est connecté à Discord!

Enfin, dirigez-vous vers Discord pour le tester:

Discord: Citations de Brooklyn Nine-Nine

Génial! Maintenant que vous avez découvert différentes manières de gérer certains événements Discord courants, vous allez apprendre à gérer les erreurs que les gestionnaires d'événements peuvent générer.

Gestion des exceptions

Comme vous l’avez déjà vu, discord.py est un système événementiel. Cet accent mis sur les événements s'étend même aux exceptions. Lorsqu'un gestionnaire d'événements déclenche une Exception, Appels discordants on_error ().

Le comportement par défaut de on_error () est d'écrire le message d'erreur et trace de pile à stderr. Pour le tester, ajoutez un gestionnaire de messages spécial à on_message ():

# bot.py
importation os
importation au hasard

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

client = discorde.Client()

@client.un événement
async def on_ready():
    impression(F'client.user.name    s'est connecté à Discord!)

@client.un événement
async def on_member_join(membre):
    attendre membre.create_dm()
    attendre membre.dm_channel.envoyer(
        F'Salut nom de membre, bienvenue sur mon serveur Discord! '
    )

@client.un événement
async def on_message(message):
    si message.auteur == client.utilisateur:
        revenir

    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    si message.contenu == '99! ':
        réponse = au hasard.choix(brooklyn_99_quotes)
        attendre message.canal.envoyer(réponse)
    elif message.contenu == 'augmenter-exception':
        élever discorde.DiscordException

client.courir(jeton)

Le nouveau lever-exception gestionnaire de messages vous permet d'élever un DiscordException sur commande.

Exécutez le programme et tapez lever-exception dans le canal Discord:

Discord: Raise Exception Message

Vous devriez maintenant voir le Exception qui a été soulevé par votre on_message () gestionnaire dans la console:

$ bot.py python
RealPythonTutorialBot s'est connecté à Discord!
Ignorer l'exception dans on_message
Traceback (dernier appel le plus récent):
        Fichier "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/client.py", ligne 255, dans _run_event
                wait coro (* args, ** kwargs)
        Fichier "bot.py", ligne 42, dans on_message
                soulève discord.DiscordException
discord.errors.DiscordException

L'exception a été interceptée par le gestionnaire d'erreurs par défaut. La sortie contient donc le message. Ignorer l'exception dans on_message. Corrigeons cela en traitant cette erreur particulière. Pour ce faire, vous allez attraper le DiscordException et écrivez-le dans un fichier à la place.

le on_error () gestionnaire d'événements prend la un événement comme premier argument. Dans ce cas, nous attendons le un événement être 'on_message'. Il accepte aussi * args et ** kwargs en tant qu'arguments flexibles, de position et de mot clé transmis au gestionnaire d'événements d'origine.

Donc, depuis on_message () prend un seul argument, message, nous attendons args[0] être le message que l'utilisateur a envoyé dans le canal Discord:

@client.un événement
async def on_error(un événement, *args, **Kwargs):
    avec ouvrir('err.log', 'une') comme F:
        si un événement == 'on_message':
            F.écrire(F'Message non traité: args[0] n')
        autre:
            élever

Si la Exception originaire du on_message () gestionnaire d'événements, vous .écrire() une chaîne formatée dans le fichier err.log. Si un autre événement soulève une Exceptionalors nous voulons simplement que notre gestionnaire relance l'exception pour appeler le comportement par défaut.

Courir bot.py et envoyer le lever-exception message à nouveau pour voir la sortie dans err.log:

$ cat err.log
Message non traité: <Message id = 573845548923224084 pinned = False auteur = <Identifiant du membre = 543612676807327754 name = 'alexronquillo' discriminator = '0933' bot = False nick = Aucun guild =>>

Au lieu d’une trace de pile, vous avez une erreur plus informative, montrant le message qui a causé on_message () pour élever le DiscordException, enregistré dans un fichier pour une persistance plus longue.

Maintenant que vous avez une expérience de la gestion d’événements différents et de l’interaction avec les API Discord, vous en apprendrez plus sur une sous-classe de Client appelé Bot, qui implémente des fonctionnalités pratiques spécifiques à un bot.

Connecter un bot

UNE Bot est une sous-classe de Client Cela ajoute un peu de fonctionnalité supplémentaire qui est utile lorsque vous créez des utilisateurs de bot. Par exemple, un Bot peut gérer des événements et des commandes, invoquer des vérifications de validation, etc.

Avant d'entrer dans les fonctionnalités spécifiques à Botconvertir bot.py utiliser un Bot au lieu d'une Client:

# bot.py
importation os
importation au hasard
de DOTENV importation load_dotenv

# 1
de discord.ext importation commandes

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

# 2
bot = commandes.Bot(préfixe de commande='!')

@bot.un événement
async def on_ready():
    impression(F'bot.user.name    s'est connecté à Discord!)

bot.courir(jeton)

Comme vous pouvez le voir, Bot peut gérer les événements de la même manière que Client Est-ce que. Cependant, notez les différences entre Client et Bot:

  1. Bot est importé du commandes discord.ext module.
  2. le Bot l'initialiseur nécessite un préfixe de commande, que vous en apprendrez plus dans la section suivante.

La bibliothèque d'extensions, poste, offre plusieurs composants intéressants pour vous aider à créer un Discord Bot. Un de ces composants est le Commander.

En utilisant Bot Les commandes

En termes généraux, un commander est une commande qu'un utilisateur donne à un bot pour qu'il fasse quelque chose. Les commandes sont différentes des événements car elles sont:

  • Défini arbitrairement
  • Appelé directement par l'utilisateur
  • Flexible, en termes d'interface

En termes techniques, un Commander est un objet qui encapsule une fonction appelée par une commande de texte dans Discord. La commande de texte doit commencer par le préfixe de commande, défini par le Bot objet.

Jetons un coup d’œil à un vieil événement pour mieux comprendre à quoi cela ressemble:

# bot.py
importation os
importation au hasard

importation discorde
de DOTENV importation load_dotenv

load_dotenv()
JETON = os.getenv('DISCORD_TOKEN')

client = discorde.Client()

@client.un événement
async def on_message(message):
    si message.auteur == client.utilisateur:
        revenir

    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    si message.contenu == '99! ':
        réponse = au hasard.choix(brooklyn_99_quotes)
        attendre message.canal.envoyer(réponse)

client.courir(JETON)

Ici, vous avez créé un on_message () gestionnaire d'événement, qui reçoit le message string et le compare à une option prédéfinie: '99! '.

Utilisant un Commander, vous pouvez convertir cet exemple pour être plus spécifique:

# bot.py
importation os
importation au hasard

de discord.ext importation commandes
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

bot = commandes.Bot(préfixe de commande='!')

@bot.commander(prénom='99')
async def neuf_nine(ctx):
    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    réponse = au hasard.choix(brooklyn_99_quotes)
    attendre ctx.envoyer(réponse)

bot.courir(jeton)

Il y a plusieurs caractéristiques importantes à comprendre sur l'utilisation de Commander:

  1. À la place d'utiliser bot.event comme avant, vous utilisez bot.command (), en passant la commande d’invocation (prénom) comme argument.

  2. La fonction ne sera appelée que lorsque ! 99 est mentionné dans le chat. Ceci est différent de la on_message () événement, qui était exécuté chaque fois qu'un utilisateur envoyait un message, quel que soit son contenu.

  3. La commande doit être précédée du point d’exclamation (! ) parce que c’est le préfixe de commande que vous avez défini dans l'initialiseur pour votre Bot.

  4. Tout Commander fonction (techniquement appelé un rappeler) doit accepter au moins un paramètre, appelé ctx, qui est le Le contexte entourant l'invoqué Commander.

UNE Le contexte détient des données telles que le canal et la guilde que l'utilisateur a appelé le Commander de.

Exécutez le programme:

Avec votre bot en marche, vous pouvez maintenant vous diriger vers Discord pour essayer votre nouvelle commande:

Discord: Brooklyn Nine-Nine Command

Du point de vue de l’utilisateur, la différence pratique réside dans le fait que le préfixe aide à formaliser la commande au lieu de simplement réagir à un problème particulier. on_message () un événement.

Cela vient également avec d'autres avantages. Par exemple, vous pouvez invoquer le Aidez-moi commande pour voir toutes les commandes que votre Bot poignées:

Discord: commande d'aide

Si vous souhaitez ajouter une description à votre commande afin que le Aidez-moi message est plus informatif, il suffit de passer un Aidez-moi description au .commander() décorateur:

# bot.py
importation os
importation au hasard

de discord.ext importation commandes
de DOTENV importation load_dotenv

load_dotenv()
jeton = os.getenv('DISCORD_TOKEN')

bot = commandes.Bot(préfixe de commande='!')

@bot.commander(prénom='99', Aidez-moi="Répond avec une citation aléatoire de Brooklyn 99")
async def neuf_nine(ctx):
    brooklyn_99_quotes = [[[[
        'JE 'm la forme humaine de la 💯 emoji.,
        'Bingpot!',
        (
            'Cool. Cool cool cool cool cool cool cool, '
            'sans doute sans doute sans doute sans doute.'
        ),
    ]

    réponse = au hasard.choix(brooklyn_99_quotes)
    attendre ctx.envoyer(réponse)

bot.courir(jeton)

Maintenant, quand l’utilisateur invoque le Aidez-moi commande, votre bot présentera une description de votre commande:

Discord: Description de l'aide informative

Gardez à l'esprit que toutes ces fonctionnalités n'existent que pour le Bot sous-classe, pas le Client superclasse.

Commander a une autre fonctionnalité utile: la possibilité d’utiliser un Convertisseur pour changer les types de ses arguments.

Conversion automatique des paramètres

L’utilisation des commandes présente un autre avantage: la possibilité de convertir paramètres.

Vous avez parfois besoin d'un paramètre pour être d'un certain type, mais des arguments à un Commander fonction sont, par défaut, des chaînes. UNE Convertisseur vous permet de convertir ces paramètres au type que vous attendez.

Par exemple, si vous voulez construire un Commander for your bot user to simulate rolling some dice (knowing what you’ve learned so far), you might define it like this:

@bot.commander(prénom='roll_dice', Aidez-moi='Simulates rolling dice.')
async def rouleau(ctx, number_of_dice, number_of_sides):
     = [[[[
        str(au hasard.choix(intervalle(1, number_of_sides + 1)))
        pour _ dans intervalle(number_of_dice)
    ]
    attendre ctx.envoyer(', '.joindre())

You defined rouleau to take two parameters:

  1. The number of dice to roll
  2. The number of sides per die

Then, you decorated it with .command() so that you can invoke it with the !roll_dice command. Finally, you .send() the results in a message back to the canal.

While this looks correct, it isn’t. Unfortunately, if you run bot.py, and invoke the !roll_dice command in your Discord channel, you’ll see the following error:

$ python bot.py
Ignoring exception in command roll_dice:
Traceback (most recent call last):
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 63, in wrapped
                ret = await coro(*args, **kwargs)
        File "bot.py", line 40, in roll
                for _ in range(number_of_dice)
TypeError: 'str' object cannot be interpreted as an integer

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/bot.py", line 860, in invoke
                await ctx.command.invoke(ctx)
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 698, in invoke
                await injected(*ctx.args, **ctx.kwargs)
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 72, in wrapped
                raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: 'str' object cannot be interpreted as an integer

En d'autres termes, range() can’t accept a str as an argument. Instead, it must be an int. While you could cast each value to an int, there is a better way: you can use a Converter .

Dans discord.py, a Converter is defined using Python 3’s function annotations:

@bot.commander(prénom='roll_dice', Aidez-moi='Simulates rolling dice.')
async def rouleau(ctx, number_of_dice: int, number_of_sides: int):
     = [[[[
        str(au hasard.choix(intervalle(1, number_of_sides + 1)))
        pour _ dans intervalle(number_of_dice)
    ]
    attendre ctx.envoyer(', '.joindre())

You added : int annotations to the two parameters that you expect to be of type int. Try the command again:

Discord: Bot Dice-Rolling Command

With that little change, your command works! The difference is that you’re now converting the command arguments to int, which makes them compatible with your function’s logic.

Next, you’ll learn about the Check object and how it can improve your commands.

Checking Command Predicates

UNE Check is a predicate that is evaluated before a Commander is executed to ensure that the Context entourant le Commander invocation is valid.

In an earlier example, you did something similar to verify that the user who sent a message that the bot handles was not the bot user, itself:

si message.auteur == client.utilisateur:
    revenir

le commandes extension provides a cleaner and more usable mechanism for performing this kind of check, namely using Check objects.

To demonstrate how this works, assume you want to support a command !create_channel that creates a new channel. However, you only want to allow administrators the ability to create new channels with this command.

First, you’ll need to create a new member role in the admin. Go into the Discord guild and select the Server Name → Server Settings menu:

Discord: Server Settings Screen

Then, select Roles from the left-hand navigation list:

Discord: Navigate to Roles

Finally select the + sign next to ROLES and enter the name admin and select Save Changes:

Discord: Create New Admin Role

Now, you’ve created an admin role that you can assign to particular users. Next, you’ll update bot.py à Check the user’s role before allowing them to initiate the command:

# bot.py
importation os

importation discorde
de discord.ext importation commandes
de dotenv importation load_dotenv

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')

bot = commandes.Bot(command_prefix='!')

@bot.commander(prénom='create-channel')
@commands.has_role('admin')
async def create_channel(ctx, channel_name='real-python'):
    guilde = ctx.guilde
    existing_channel = discorde.utils.obtenir(guilde.canaux, prénom=channel_name)
    si ne pas existing_channel:
        impression(F'Creating a new channel: channel_name')
        attendre guilde.create_text_channel(channel_name)

bot.courir(TOKEN)

Dans bot.py, you have a new Commander function, called create_channel() which takes an optional channel_name and creates that channel. create_channel() is also decorated with a Check appelé has_role().

You also use discord.utils.get() to ensure that you don’t create a channel with the same name as an existing channel.

If you run this program as it is and type !create-channel into your Discord channel, then you’ll see the following error message:

$ python bot.py
Ignoring exception in command create-channel:
Traceback (most recent call last):
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/bot.py", line 860, in invoke
                await ctx.command.invoke(ctx)
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 691, in invoke
                await self.prepare(ctx)
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 648, in prepare
                await self._verify_checks(ctx)
        File "/Users/alex.ronquillo/.pyenv/versions/discord-venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 598, in _verify_checks
                raise CheckFailure('The check functions for command 0.qualified_name failed.'.format(self))
discord.ext.commands.errors.CheckFailure: The check functions for command create-channel failed.

Ce CheckFailure dit ça has_role('admin') failed. Unfortunately, this error only prints to stdout. It would be better to report this to the user in the channel. To do so, add the following event:

@bot.un événement
async def on_command_error(ctx, Erreur):
    si isinstance(Erreur, commandes.les erreurs.CheckFailure):
        attendre ctx.envoyer('You do not have the correct role for this command.')

This event handles an error event from the command and sends an informative error message back to the original Context of the invoked Commander.

Try it all again, and you should see an error in the Discord channel:

Discord: Role Check Error

Génial! Now, to resolve the issue, you’ll need to give yourself the admin role:

Discord: Grant Admin Role

Avec le admin role, your user will pass the Check and will be able to create channels using the command.

When you type !create-channel again, you’ll successfully create the channel real-python:

Discord: Navigate to New Channel

Also, note that you can pass the optional channel_name argument to name the channel to whatever you want!

With this last example, you combined a Commander, an event, a Check, and even the get() utility to create a useful Discord bot!

Conclusion

Toutes nos félicitations! Now, you’ve learned how to make a Discord bot in Python. You’re able to build bots for interacting with users in guilds that you create or even bots that other users can invite to interact with their communities. Your bots will be able to respond to messages and commands and numerous other events.

In this tutorial, you learned the basics of creating your own Discord bot. You now know:

  • What Discord is
  • Pourquoi discord.py is so valuable
  • How to make a Discord bot in the Developer Portal
  • How to create a Discord connection in Python
  • How to handle events
  • How to create a Bot lien
  • How to use bot commands, checks, and converters

To read more about the powerful discord.py library and take your bots to the next level, read through their extensive documentation. Also, now that you’re familiar with Discord APIs in general, you have a better foundation for building other types of Discord applications.