鹿野川ダムと野村ダムと肱川をスクレイピング

インストール

pip install requests
pip install python-twitter
pip install apscheduuler
pip install beautifulsoup4

プログラムを実行すると8,18,28,38,48,58分に表示 コメントアウトしているTwitterのキーを入力すると投稿できます

import datetime

import requests
import twitter
from apscheduler.schedulers.blocking import BlockingScheduler
from bs4 import BeautifulSoup


# 文字を小数点に変換、変換できない場合は0.0
def moji_float(x):

    try:
        result = float(x.rstrip('↑↓→'))
    except:
        result = 0.0

    return result


# 空文字の場合、前の値で補間、次の値で補間
def ffill_bfill(data):

    # ffill
    for y in range(1, len(data)):
        for x in range(len(data[y])):
            if not data[y][x]:
                data[y][x] = data[y - 1][x]

    # bfill
    for y in range(len(data) - 1)[::-1]:
        for x in range(len(data[y])):
            if not data[y][x]:
                data[y][x] = data[y + 1][x]

    return data


# 現在と過去を比較し記号に変換
def moji_sign(now, before):

    if now > before:
        result = ' ↗'
    elif now < before:
        result = ' ↘'
    else:
        result = ''
    return result


def alert_level(now, wl):

    alert = [' 水防団待機水位', ' はん濫注意水位', ' 避難判断水位', ' はん濫危険水位', ' 計画高水位']

    temp = [[i, j] for i, j in zip(wl, alert) if i]

    for i, j in temp[::-1]:
        if now >= i:
            result = j
            break
    else:
        result = ''

    return result


def scraping(url, tag):

    headers = {
        'User-Agent':
        'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'
    }

    r = requests.get(url, headers=headers)

    if r.status_code == requests.codes.ok:

        soup = BeautifulSoup(r.content, 'html5lib')

        data = []

        for trs in soup.select(tag):

            # 列 => セル => セル内の列 => セル内のセル の順に取得
            table = [[[td.get_text(strip=True) for td in tr.select('td')]
                      for tr in tds.select('tr')]
                     for tds in trs.select('td > table > tbody')]

            for i in map(list, zip(*table)):
                temp = sum(i, [])
                data.append(temp[0:2] + list(map(moji_float, temp[2:])))

        res_data = ffill_bfill(data)
        res_sign = list(map(moji_sign, res_data[-1], res_data[-2]))

        return (res_data[-1], res_sign)


sched = BlockingScheduler()


@sched.scheduled_job('cron', minute='8,18,28,38,48,58')
def timer_job():

    # 現在の時刻から-5分し、10分単位に調整
    dt_now = datetime.datetime.now() - datetime.timedelta(minutes=5)
    dt_now -= datetime.timedelta(minutes=(dt_now.minute % 10))

    # 南予北部 Page1/3 URL
    river_url = 'http://183.176.244.72/cgi/050_HQ_030_01.cgi?GID=050_HQ_030&UI=U777&SI=00000&LO=88&SRO=1&KKB=101100&DSP=11110&SKZ=111&NDT=1&MNU=1&BTY=IE6X&SSC=0&RBC=100&DT={}&GRP=USR022&TPG=3&PG=1&KTM=3'.format(
        dt_now.strftime('%Y%m%d%H%M'))

    # 河川情報をスクレイピング
    river_now, river_sign = scraping(
        river_url, 'body > table:nth-of-type(9) > tbody > tr')

    # 大洲第二 危険水位
    oozu2_alert = alert_level(river_now[2], [2.8, 3.8, 4.8, 5.8, 8.51])

    # 五郎 危険水位
    goro_alert = alert_level(river_now[5], [5.2, 6.5, 0.0, 0.0, 11.00])

    # 新谷 危険水位
    niya_alert = alert_level(river_now[7], [1.5, 2.20, 2.65, 3.15, 4.12])

    # 肱川の水位
    twit_river = '【肱川】\n大洲第二:{0[2]:.2f}m{1[2]}{2}\n五郎:{0[5]:.2f}m{1[5]}{3}\n新谷:{0[7]:.2f}m{1[7]}{4}'.format(
        river_now, river_sign, oozu2_alert, goro_alert, niya_alert)

    # 鹿野川ダム URL
    kano_dam_url = 'http://183.176.244.72/cgi/170_USER_010_01.cgi?GID=170_USER_010&UI=U777&SI=00000&MNU=1&LO=88&BTY=IE6X&NDT=1&SK=0000000&DT={}&GRP=USR010&TPG=1&PG=1&KTM=3'.format(
        dt_now.strftime('%Y%m%d%H%M'))

    # 鹿野川ダム スクレイピング
    kano_dam_now, kano_dam_sign = scraping(
        kano_dam_url, 'body > table:nth-of-type(7) > tbody > tr')

    # 鹿野川ダム 危険水位
    if kano_dam_now[2] >= 87.50:
        kano_dam_alert = ' 防災操作開始水位'
    else:
        kano_dam_alert = ''

    # 鹿野川ダムの情報
    twit_kano_dam = '【鹿野川ダム】\n貯水位:{0[2]:.2f}{1[2]}{2}\n全流入量:{0[3]:.2f}{1[3]}\n全放流量:{0[4]:.2f}{1[4]}\n貯水量:{0[5]}{1[5]}'.format(
        kano_dam_now, kano_dam_sign, kano_dam_alert)

    # 野村ダム URL
    nomu_dam_url = 'http://183.176.244.72/cgi/170_USER_010_01.cgi?GID=170_USER_010&UI=U777&SI=00000&MNU=1&LO=88&BTY=IE6X&NDT=1&SK=0000000&DT={}&GRP=USR011&TPG=1&PG=1&KTM=3'.format(
        dt_now.strftime('%Y%m%d%H%M'))

    # 野村ダム スクレイピング
    nomu_dam_now, nomu_dam_sign = scraping(
        nomu_dam_url, 'body > table:nth-of-type(7) > tbody > tr')

    # 野村ダム 危険水位
    if nomu_dam_now[2] >= 169.4:
        nomu_dam_alert = ' 防災操作開始水位'
    else:
        nomu_dam_alert = ''

    # 野村ダムの情報
    twit_nomu_dam = '【野村ダム】\n貯水位:{0[2]:.2f}{1[2]}{2}\n全流入量:{0[3]:.2f}{1[3]}\n全放流量:{0[4]:.2f}{1[4]}\n貯水量:{0[5]}{1[5]}'.format(
        nomu_dam_now, nomu_dam_sign, nomu_dam_alert)

    # 日付
    twit_date = '{}現在'.format(dt_now.strftime('%Y/%m/%d %H:%M'))

    # ツイート文字結合
    twit = '\n\n'.join([
        twit_date,
        twit_kano_dam,
        twit_nomu_dam,
        twit_river,
    ]).strip()

    print(len(twit))
    print(twit)


"""
    api = twitter.Api(
        consumer_key='',
        consumer_secret='',
        access_token_key='',
        access_token_secret='')

    status = api.PostUpdate(
        twit,
        media='http://www.pref.ehime.jp/kasen/Jpeg/Cam009/00_big.jpg')
"""

sched.start()