1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

都内のコロナ感染者数を指定時刻に報告してくれるDiscordのBotをDocker上で作成してみた

Posted at

2020年の新卒でIT系に勤めています。Qiitaでの初投稿なので至らない点もあると思いますがよろしくお願いします。

目的

discordApiを用いたbot作りにはまったため、スクレイピングの練習もかねてタイトルのようなbotを作成してみた。

実行環境

Windows

  • windows10
  • Python3.7.3

VPS

  • CentOS 7

手順

Windows上で構築し、botの動作を確認する

botのトークン取得などは他の記事でたくさん書かれているので省略します。以下のコマンドで使用するライブラリをインストール
pip install beautifulsoup4
pip install requests
pip install discord
今回スクレイピングの対象とするサイトは、東京都の新型コロナウイルス感染症対策サイトです。
まずは、BeautifulSoupでほしいデータが取れるか検証してみます。ソースコードは以下のよう。

soup.py

import requests
from bs4 import BeautifulSoup

#getでURLに接続しデータを取得
res= requests.get("https://stopcovid19.metro.tokyo.lg.jp/cards/number-of-confirmed-cases/")

#オブジェクトを格納
soup = BeautifulSoup(res.text,"html.parser")

#ほしい部分のタグおよびクラスでフィルターをかける、extractを使っていらない部分の除去
con = soup.find("span",class_="DataView-DataInfo-summary")
con=soup.find("small",class_="DataView-DataInfo-summary-unit").extract()

text=con.get_text()

text= text.strip()


print(text+"人です")

これを実行してみると
image.png
しっかりと取得できていて、空白なども消せていました。

次にこれをdiscordのbotプログラムに組み込んでいきます。
discord.pyに入っているループ機能を使用して60秒に一回ループ、かつその中で指定した時刻になったらスクレイピングしテキストチャンネルに投稿というプログラムを組みました。ソースは以下のよう。

bot.py
#coding:UTF-8
import discord
from discord.ext import tasks
from datetime import datetime
import requests
from bs4 import BeautifulSoup

TOKEN = "hoge" #トークン
CHANNEL_ID = hoge #チャンネルID 

# 接続に必要なオブジェクトを生成
client = discord.Client()

# 60秒に一回ループ
@tasks.loop(seconds=60)
async def loop():    
    now = datetime.now().strftime('%H:%M')
    
    if now == '20:05':
        await client.wait_until_ready()
        channel = client.get_channel(CHANNEL_ID)
        #先ほどのコード(soup.py)
        res= requests.get("https://stopcovid19.metro.tokyo.lg.jp/cards/number-of-confirmed-cases/")
        soup = BeautifulSoup(res.text,"html.parser")
        con = soup.find("span",class_="DataView-DataInfo-summary")
        con=soup.find("small",class_="DataView-DataInfo-summary-unit").extract()
        text=con.get_text()
        text= text.strip() 

        await channel.send("本日の東京都の感染者数は"+text+"人です") 

 #おまけ部分。指定したワードに反応してコメントを返す機能       
@client.event
async def on_message(message):
    # メッセージ送信者がBotだった場合は無視
    if message.author.bot:
        return
    # 「新宿」と発言したら「密」が返ってくる
    if message.content == '新宿':
        await message.channel.send('密です')
    
    if message.content == '江戸川区':
        await message.channel.send('密です')

#ループ処理実行
loop.start()
# Bot起動
client.run(TOKEN)

時刻を20:05にしてるのは、今回使用しているサイトの感染者数の更新が20時であると推測したため。
実行結果
image.png

※サイトには20時と書いてありましたが、日によってまちまちで今回は10分ほどであったためこのような結果になりました。設定時刻は余裕をもって20時30分とかがよさそう。
動作の確認ができたので、これをVPSのDocker上で起動します。

Dockerに輸送

docker run -it --name hoge python /bin/bash
でpython環境を構築
docker exec -it hoge bash
で中にもぐって作業開始。
まずは、pipで必要なライブラリをインストール。
pip install beautifulsoup4
pip install requests
pip install discord
vimがなくて編集できないので
apt-get update
apt-get install vim
で入れます。
デフォルトのタイムゾーンがUTCなので
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
このコマンドを使用してタイムゾーンを変更。
その後適当にフォルダ作ってその中にbot.pyをつくり先ほどのソースをコピペします。これで完成。
python bot.pyで起動すればdiscord上にbotが立ち上がり、指定時刻に都内の本日のコロナ感染者数を報告してくれます!

改善点

今回はサイトが20時に更新されると推測し決め打ちを行っていますが、理想形はサイトが更新されると同時にスクレイピングを行いbotが報告してくれるという形です。
ループの中で、そのループで取得してきたやつと前回取得したデータを比較し一致したらそのまま違ったら更新しbotが報告する、というプログラムを書けばできそうだなーと思ったので改善したらまた別の記事にまとめて投稿します。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?