Help us understand the problem. What is going on with this article?

お気に入り種牡馬の産駒の出走予定をLineに通知する

More than 1 year has passed since last update.

はじめに

皆さん、競馬楽しんでいますか? (笑)

以前、エスポワールシチーという馬の一口馬主をやっておりまして…
エスポワールシチーは引退後、無事種牡馬に上がり、昨年から子供たちがレースに出始めています。

一口馬主で持っている馬たちは扶養(?)しているということもあり「子供の運動会」を見る感じでレースを楽しんでいたのですが、その子供たちがレースに出るとなると「孫の運動会」になるわけです(笑)

その「孫の運動会」を見逃さないように、孫たち(?)の出走が決まったら、Lineに通知するような環境を構築してみました。

環境の概要

  • 公益社団法人日本軽種馬協会さんが提供しているJBIS-Searchの「種牡馬情報:産駒出走情報」を元データに使わせていただきました。
  • JBIS-Searchからrequestsを使って取得したデータからBeautifulSoupを使って必要な情報を抽出。
  • 通知したい文章に整形し直した上で、LINE Notifyを使って自分宛てに通知。
  • Heroku Schedulerを使って上記処理を定時実行。

なお、今回は以下の記事を参考に実装しています。
非常に参考になりました。ありがとうございます。

Pythonで少し詳しいお天気情報をLINEに通知する (1)
Pythonで少し詳しいお天気情報をLINEに通知する (2)
Herokuでお天気Pythonの定期実行

開発時のライブラリ等のバージョン

  • Python 3.7.1
  • beautifulsoup4 4.6.3
  • mojimoji 0.0.8
  • python-dotenv 0.9.1
  • requests 2.20.1

実装

産駒出走情報の取得、抽出

requestsを使ってJBIS-Searchさんから情報取得、BeautifulSoupを使って必要な情報を抽出、1頭1頭の情報をnamedtupleに入れてyieldで返す関数を作ってみました。
本当は異常系に対する実装すべきですがそこは追々…

jbis.py
"""JBISへのアクセス関数群."""
import re
import datetime
from collections import namedtuple

import requests
from bs4 import BeautifulSoup


def iter_sire_entries(horseid):
    """指定されたIDの種牡馬の産駒の出走予定を返す."""
    r = requests.get(f'https://www.jbis.or.jp/horse/{horseid}/sire/entry/')
    soup = BeautifulSoup(r.content, "html.parser")
    h2s = soup.find_all('h2')
    today = datetime.date.today()

    Entry = namedtuple(
        'Entry', ['date', 'course', 'raceno', 'racename', 'horsename'])

    for h2 in h2s:
        m = re.fullmatch(r"\s?([0-9]{1,2})月\s?([0-9]{1,2})日出走分", h2.string)
        month = int(m.group(1))
        day = int(m.group(2))
        date = datetime.date(
            today.year + (0 if today.month <= month else 1), month, day)

        for tr in h2.find_next('tbody').find_all('tr'):
            tds = tr.find_all('td')
            entry = Entry(date, tr.find('th').string,
                          tds[0].string, tds[1].text.strip(), tds[7].string)
            yield entry

通知したい文章に整形

上の関数で取得した出走予定を日付でグループ化、それを更にレースごとにグループ化して文章を作っています。
groupbyを使うには、事前にキーでソートされている必要がありますが、JBIS-Searchで取得した時点で少なくとも日付ではソート済み、レースごとは確証はないものの、まぁソート済みだろう…という感じなのでその前提で…
あと元のコンテンツがアルファベット等が全角になっていますので、カナ以外は半角にするため、mojimojiを使わせてもらっています。

espoircity_child_entry.py
def main():
    """メイン関数."""
    p = ArgumentParser(description='エスポワールシチー産駒の出走予定をLINE Notifyに送る')
    p.add_argument('-d', '--debug', action='store_true', help='デバッグ用')
    args = p.parse_args()

    content = f'エスポワールシチー産駒の出走予定\n'

    for date, g in groupby(jbis.iter_sire_entries('0000888832'), lambda e: e.date):
        content += f'\n{date.strftime("%m/%d")}\n'
        for r, g2 in groupby(g, lambda x: (x.course, x.raceno, x.racename)):
            racename = mojimoji.zen_to_han(r[2], kana=False)
            content += f' {r[0]}{r[1]}R {racename}\n'
            for e in g2:
                content += f'  {e.horsename}\n'

    if args.debug:
        print(content)
    else:
        line.notify(settings.NOTIFY_ACCESS_TOKEN, content)

LINE Notifyを使っての通知

LINE Notifyについてはリンク先を参照のこと。

LINE Notifyを使っての通知はトークンさえ作れれば非常に簡単。

line.py
"""LINEへのアクセス関数群."""
import requests


def notify(token, message):
    """LINE Notifyでメッセージを送る."""
    payload = {'message': message}
    headers = {'Authorization': 'Bearer ' + token}
    requests.post('https://notify-api.line.me/api/notify',
                  data=payload, headers=headers)

トークンに関してはソース直書きするのはちょっと…なので、python-dotenvを使って、.envファイル、もしくは環境変数から取得するようにしました。

settings.py
"""設定情報."""
import os
from os.path import dirname, join

from dotenv import load_dotenv

dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)

NOTIFY_ACCESS_TOKEN = os.environ.get("NOTIFY_ACCESS_TOKEN")

使う側は以下のようにすればOK.

espoircity_child_entry.py
import settings

(省略)

line.notify(settings.NOTIFY_ACCESS_TOKEN, content)

Heroku Schedulerを使っての定時実行

ここに関しては完全にHerokuでお天気Pythonの定期実行のままの内容になります。わかりやすい記事で感謝です。
この記事のおかげもありますが、Herokuってこんなに楽にデプロイできるのね…というのが実感…

完成!

実際に12/4に通知されたLINEのキャプチャです。これでお気に入り種牡馬の産駒の出走予定を見逃さなくて済みますね!

Screenshot_20181204-213756.jpg

なお、ソースはgithubの方においてあります。

最後に

競馬もコンピュータを使って快適に楽しみましょう!(笑)

masaminh
40代エンジニアです。AWSソリューションアーキテクト-アソシエイト。 業務ではC#/C++中心ですが、趣味で書くプログラムはPythonで書いてます。 最近Node.js始めました。
http://masaminh.oumanoshasin.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした