[Concept] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py

1/30 postscript It was completed [Completed] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py

at first

This is Qiita's first post. My name is Ryo, also known as fctokyo1016. Twitter → @ fctokyo1016 I usually develop with PHP. It's a code that was made by an amateur who has been an engineer for several years, so I hope you can overlook it.

Background of trying to make

--Nico Nico Live Broadcasting Planning team to which about 10 people belong, each of whom can freely broadcast live in the same community ――Since the alert of Nico Nama can no longer be used due to the specification change, it is troublesome to find the URL when watching the broadcast of other members. ――Isn't it easier if a notification comes to the Discord server where all the members are located? --Sites such as Twitch and Youtube Live already have existing bots, but they do not support Nico Nico. ――Isn't it possible to make a fake (self-made) somehow?

Difficulties

--As mentioned above, due to changes in Nico Nico Live's alert specifications, neither RSS nor API support live user broadcasting.

idea

――Can you use scraping that you touched a little in the past? ――I just wanted to study Python

Referenced articles

-Practical Discord Bot in Python (discordpy explanation)

Execution result

The broadcast of our members was actually notified Discord_2020-01-15_01-02-13.png

code

discordbot.py


import requests
import os.path
import re
import discord
import asyncio
from bs4 import BeautifulSoup

#Specify file path for notification management
listFilePath = 'list.txt'

#Replace with your bot's access token
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

#Any channel ID(int)
CHANNEL_ID = 0000000000000000

#Set the community you want to check
targetCommunitys = ['co1520016']

#Returns True if there is a search in the list and False if there is none
def searchList(liveURL):
    #File existence check
    if not os.path.exists(listFilePath):
        return False

    liveLV = liveIdExtraction(liveURL)

    #In-file check
    with open(listFilePath) as f:
        for i, line in enumerate(f):
            if line == liveLV + '\n':
                return True
    print(line)
    return False

#Add broadcast ID to the list
def addList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    with open(listFilePath, 'a') as f:
        print(liveLV, file=f)

#Broadcast ID from the broadcast URL(lvXXXXXXX)Extraction
def liveIdExtraction(liveURL):
    repatter = re.compile('lv[0-9]+')
    return repatter.search(liveURL).group()

#Get broadcast title from broadcast URL
def getLiveTitle(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    for meta_tag in soup.find_all('meta', attrs={'property': 'og:title'}):
        return meta_tag.get('content')

#Obtaining the broadcaster name from the broadcast URL
def getLiveName(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    return soup.find("span",{"class":"name"}).text



#Generate the objects needed for the connection
client = discord.Client()

#Processing that operates at startup
@client.event
async def on_ready():
    while(True):
        #Repeat for the number of target communities
        for targetCommunity in targetCommunitys:
            #Set URL
            r = requests.get("https://com.nicovideo.jp/community/" + targetCommunity)

            #Check the community TOP page
            soup = BeautifulSoup(r.content, "html.parser")
            result = soup.find("section", "now_live")

            #If the broadcast has started
            if result is not None:
                #Broadcast URL acquisition
                liveURL = result.find("a", "now_live_inner").get("href")

                #Search in the list and do not process if the broadcast ID has already been processed
                if searchList(liveURL) is False:
                    #Broadcast title acquisition
                    liveTitle = getLiveTitle(liveURL)
                    #Broadcaster name acquisition
                    liveName = getLiveName(liveURL)

                    #Send to Discord
                    channel = client.get_channel(CHANNEL_ID)
                    await channel.send('@everyone ' + liveName + 'Has started delivery\n\n' + liveTitle + '\n' + liveURL)

                    #Broadcast ID postscript
                    addList(liveURL)

        #Wait 1 minute
        await asyncio.sleep(60)

#Connect to Discord
client.run(TOKEN)

What you are doing

--Scraping the community page of Nico Nico Live Broadcasting to get the broadcasting URL --Notify Discord --Leave the notified broadcast in a text file so that it will not be notified again

Specify the file name of the text file that leaves the broadcast once processed. as you like

discordbot.py


#Specify file path for notification management
listFilePath = 'list.txt'

Discord setting system

discordbot.py


#Replace with your bot's access token
TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

#Any channel ID(int)
CHANNEL_ID = 0000000000000000

Specify the community to be processed as an array. Supports multiple communities

discordbot.py


#Set the community you want to check
targetCommunitys = ['co1520016']

Determine if you have already been notified from the broadcast URL It is for checking to prevent notifying the same broadcast many times.

discordbot.py


#Returns True if there is a search in the list and False if there is none
def searchList(liveURL):
    #File existence check
    if not os.path.exists(listFilePath):
        return False

    liveLV = liveIdExtraction(liveURL)

    #In-file check
    with open(listFilePath) as f:
        for i, line in enumerate(f):
            if line == liveLV + '\n':
                return True
    print(line)
    return False

Add the notified broadcast to the list

discordbot.py


#Add broadcast ID to the list
def addList(liveURL):
    liveLV = liveIdExtraction(liveURL)
    with open(listFilePath, 'a') as f:
        print(liveLV, file=f)

Various data are obtained by scraping from the broadcast URL

discordbot.py


#Broadcast ID from the broadcast URL(lvXXXXXXX)Extraction
def liveIdExtraction(liveURL):
    repatter = re.compile('lv[0-9]+')
    return repatter.search(liveURL).group()

#Get broadcast title from broadcast URL
def getLiveTitle(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    for meta_tag in soup.find_all('meta', attrs={'property': 'og:title'}):
        return meta_tag.get('content')

#Obtaining the broadcaster name from the broadcast URL
def getLiveName(liveURL):
    r = requests.get(liveURL)
    soup = BeautifulSoup(r.content, "html.parser")
    return soup.find("span",{"class":"name"}).text

Task

--I tried to actually run it on Heroku, but later I learned the specification that the local file is deleted every time it is restarted --Since the notification management file (list.txt) is deleted every time, there is a possibility that the same broadcast will be notified many times. -~~ It is necessary to have the data externally such as Google spreadsheet ~~ --Heroku seems to have a PostgreSQL database for free ――? ?? ?? "I didn't know that ..."

Recommended Posts

[Concept] bot that posts the start notification of Nico Nico Live Broadcasting to Discord on discord.py
Make a BOT that shortens the URL of Discord
Create a bot that only returns the result of morphological analysis with MeCab on Discord
Let's execute the command on time with the bot of discord
Get comments on Nico Nico Live Broadcasting
Create a bot that posts the number of people positive for the new coronavirus in Tokyo to Slack
I tried to make a translation BOT that works on Discord using googletrans
Looking back on the history of expressions that return sum of square to Pythonic