[PYTHON] Created a Discord bot to notify you of updates to become a novelist

Introduction

Isn't there Become a novelist? Frequently morphological analysis or scraping calculate the average number of characters in the title That's what I'm doing. My favorite "Shangri-La Frontier" is an irregular update, and I don't know when it will be updated, so I reload the table of contents once every two minutes. You need to check for updates. This is very annoying, so I decided to make a bot that would let me know if I had Discord open.

environment

Preparation

Go to here, get a token by Bot-> Build-A-Bot in New Application, check bot in OAuth2, and check the bot in OAuth2. Invite to the server.

create

Basic

I will make the basic part for the time being

DiscordBot.py


import discord
TOKEN = '****************'
CHANNEL_ID = ***************** #Enter the ID of the home channel
client = discord.Client()

@client.event
async def on_ready():
    await channel.send("on ready")

client.run(TOKEN)

I have a simple bot that just says "on ready" when it starts.

loop

Next, let's make the loop part. Loop with tasks.loop and hit the API with ~~ aiohttp once every 10 seconds ~~ requests. [^ 1]

DiscordBot.py


import discord
from discord.ext import tasks
import aiohttp
TOKEN = '****************'
CHANNEL_ID = ***************** #Enter the ID of the home channel
client = discord.Client()

@client.event
async def on_ready():
    loop.start()
    await channel.send("on ready")

@tasks.loop(seconds=10)
async def loop():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:

client.run(TOKEN)

API processing

Compare the "last publication date of the returned API" and the "last publication date of the API you hit (10 seconds ago)", and if they are different, judge that it has been updated and send a message to the channel.

DiscordBot.py


import discord
from discord.ext import tasks
import aiohttp
import yaml
TOKEN = '****************'
CHANNEL_ID = ***************** #Enter the ID of the home channel
client = discord.Client()
lastup = "null"

@client.event
async def on_ready():
    loop.start()
    await channel.send("on ready")

@tasks.loop(seconds=10)
async def loop():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:
            new_lastup = yaml.safe_load(await r.text())[1]["general_lastup"]
            channel = client.get_channel(CHANNEL_ID)
            global lastup
            if lastup != new_lastup:
                lastup = new_lastup
                await channel.send('Shanflo update came')
client.run(TOKEN)

For the time being, we now have a bot that will notify you when it is updated. However, in this case, the problem is that "** the variable ** lastup ** is set to null at startup, so you will get the illusion that "update has come" in the first lap of the loop immediately after startup ** ". there is.

Reinforcement of start-up processing

So, you can solve it by hitting the API once at startup and assigning it to lastup.

DiscordBot.py


import discord
from discord.ext import tasks
import aiohttp
import yaml
import datetime
TOKEN = '****************'
CHANNEL_ID = ***************** #Enter the ID of the home channel
client = discord.Client()
lastup = "null"

@client.event
async def on_ready():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:
            global lastup
            lastup = yaml.safe_load(await r.text())[1]["general_lastup"]
    loop.start()
    channel = client.get_channel(CHANNEL_ID)
    await channel.send("on ready")
    await channel.send("Last updated:" + str(lastup)) #By the way, I made it tell the last update date and time at startup

@tasks.loop(seconds=10)
async def loop():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:
            new_lastup = yaml.safe_load(await r.text())[1]["general_lastup"]
            channel = client.get_channel(CHANNEL_ID)
            global lastup
            if lastup != new_lastup:
                lastup = new_lastup
                await channel.send('Shanflo update came')
client.run(TOKEN)

bonus

It can be said that this is complete, but even though it is a chatbot, it has only a function to convey information in one direction, and there is no command that can be sent from here, so I will add one command. [How long has it been since the last update? ] I will answer with a timedelta object.

DiscordBot.py


import discord
from discord.ext import tasks
import aiohttp
import yaml
import datetime
TOKEN = '****************'
CHANNEL_ID = ***************** #Enter the ID of the home channel
client = discord.Client()
lastup = "null"

@client.event
async def on_ready():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:
            global lastup
            lastup = yaml.safe_load(await r.text())[1]["general_lastup"]
    loop.start()
    channel = client.get_channel(CHANNEL_ID)
    await channel.send("on ready")
    await channel.send("Last updated:" + str(lastup)) #By the way, I made it tell the last update date and time at startup

@client.event
async def on_message(message):
    if message.author.bot:
        return
    if message.content == '[How long has it been since the last update?]':
        dif = datetime.datetime.now() - lastup
        await message.channel.send(dif)

@tasks.loop(seconds=10)
async def loop():
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.syosetu.com/novelapi/api/?ncode=n6169dz&of=gl') as r:
            new_lastup = yaml.safe_load(await r.text())[1]["general_lastup"]
            channel = client.get_channel(CHANNEL_ID)
            global lastup
            if lastup != new_lastup:
                lastup = new_lastup
                await channel.send('Shanflo update came')
client.run(TOKEN)

That's all there is to it.

reference

[^ 1]: ~~ It seems that aiohttp that can process asynchronously is better, but I'm not sure and I thought that a little delay would be acceptable, so I made requests ~~ I changed to use aiohttp .. It is almost a complete copy of the Discord.py document.

Recommended Posts

Created a Discord bot to notify you of updates to become a novelist
Creating a LINE BOT to notify you of additional AtCoder contests using AWS
I tried to notify the update of "Become a novelist" using "IFTTT" and "Become a novelist API"
Allow Slack to notify you of the end of a time-consuming program process
How to notify a Discord channel in Python
If you want to make a discord bot with python, let's use a framework
Created a module to monitor file and URL updates
Make a BOT that shortens the URL of Discord
Let's make a Discord Bot.
I made a discord bot
If you want to become a data scientist, start with Kaggle
Created a service that allows you to search J League data
Use AWS lambda to scrape the news and notify LINE of updates on a regular basis [python]
How to make a slack bot
Have Alexa run Python to give you a sense of the future
How to send a visualization image of data created in Python to Typetalk
Make a Discord Bot that you can search for and paste images
[Python] If you want to draw a scatter plot of multiple clusters
I made a program to notify you by LINE when switches arrive