Pythonで水門水質データベースからデータをスクレイピングする方法

Pythonを使用して水位データをスクレイピングし、JSONファイルとして保存する方法について説明します。このブログでは、以下の内容をカバーします。(責任は負いません)


  1. ライブラリのインポート

  2. 水位データのスクレイピング

  3. 日付範囲の分割

  4. データの保存

1. ライブラリのインポート

まず、必要なライブラリをインポートします。以下のコードは、HTTPリクエストを送信するための`requests`、HTMLを解析するための`BeautifulSoup`、日付操作のための`datetime`と`timedelta`、およびJSONファイルを扱うための`json`をインポートします。

import requests
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
import json

2. 水位データのスクレイピング

次に、水位データを特定のステーションから指定された日付範囲内でスクレイピングする関数`scrape_water_data`を定義します。

def scrape_water_data(start_date, end_date, station_id):
    base_url = "http://www1.river.go.jp/cgi-bin/DspWaterData.exe"
    params = {
        "KIND": 1,
        "ID": station_id,
        "BGNDATE": start_date,
        "ENDDATE": end_date,
        "KAWABOU": "NO"
    }

    response = requests.get(base_url, params=params)
    soup = BeautifulSoup(response.content, 'html.parser')

    table = soup.find('table', border="1")
    rows = table.find_all('tr')

    headers = [header.text.strip() for header in rows[0].find_all('td')]
    station_data = [
        [cell.text.strip() for cell in row.find_all('td')]
        for row in rows[1:]
    ]

    iframe = soup.find('iframe')
    iframe_url = "http://www1.river.go.jp" + iframe['src']
    iframe_response = requests.get(iframe_url)
    iframe_soup = BeautifulSoup(iframe_response.content, 'html.parser')

    table = iframe_soup.find('table')
    rows = table.find_all('tr')

    iframe_headers = [header.text.strip() for header in rows[0].find_all('th')]
    iframe_data = {}

    for row in rows[1:]:
        cells = row.find_all('td')
        date_str = cells[0].text.strip()
        time_str = cells[1].text.strip()
        
        if time_str == '24:00':
            date_time = datetime.strptime(date_str, '%Y/%m/%d') + timedelta(days=1)
            date_time = date_time.replace(hour=0, minute=0)
        else:
            date_time = datetime.strptime(date_str + time_str, '%Y/%m/%d%H:%M')
        
        formatted_date_time = date_time.strftime('%Y-%m-%d %H:%M:%S')

        data = cells[2].text.strip()
        try:
            data = float(data)
        except ValueError:
            data = -100000000000000000
        iframe_data[formatted_date_time] = data

    return station_data, iframe_data

3. 日付範囲の分割

指定された日付範囲を分割し、各区間ごとにデータをスクレイピングするための関数`split_date_range_with_loop`を定義します。

def split_date_range_with_loop(start_date_str, end_date_str, interval_days=30):
    start_date = datetime.strptime(start_date_str, "%Y%m%d")
    end_date = datetime.strptime(end_date_str, "%Y%m%d")

    date_ranges = []
    current_start_date = start_date

    while current_start_date < end_date:
        current_end_date = min(current_start_date + timedelta(days=interval_days - 1), end_date)
        date_ranges.append((current_start_date.strftime("%Y%m%d"), current_end_date.strftime("%Y%m%d")))
        current_start_date = current_end_date + timedelta(days=1)

    return date_ranges

4. データの保存

スクレイピングしたデータをJSONファイルとして保存するための関数`scrape_and_save_all_data`を定義します。

def scrape_and_save_all_data(start_date_str, end_date_str, station_id, output_file):
    date_ranges = split_date_range_with_loop(start_date_str, end_date_str)
    all_iframe_data = {}

    for start_date, end_date in date_ranges:
        _, iframe_data = scrape_water_data(start_date, end_date, station_id)
        all_iframe_data.update(iframe_data)

    with open(output_file, 'w') as f:
        json.dump(all_iframe_data, f, indent=4)

実行例

最後に、上記の関数を使用して水位データをスクレイピングし、JSONファイルとして保存する例を示します。

以下の変数設定は、指定された日付範囲内で特定のステーションから水位データを取得し、JSONファイルとして保存するためのものです。

変数の説明

  1. start_date

    • `start_date = "20230701"`

    • スクレイピングを開始する日付です。ここでは2023年7月1日からデータを取得します。

    • 日付形式は`"YYYYMMDD"`です。

  2. end_date

    • `end_date = "20240712"`

    • スクレイピングを終了する日付です。ここでは2024年7月12日までデータを取得します。

    • 日付形式は`"YYYYMMDD"`です。

  3. station_id

    • `station_id = "302041282207240"`

    • 水位データを取得する特定のステーションのIDです。このIDは、各ステーション固有の識別子です。

    • 実際に使用するステーションのIDに置き換える必要があります。

  4. output_file

    • `output_file = "combined_data.json"`

    • 取得したデータを保存するファイル名です。ここでは`"combined_data.json"`という名前のJSONファイルにデータを保存します。

    • ファイル形式はJSONです。

全体の流れ

この設定に基づいて、`scrape_and_save_all_data`関数を呼び出します。この関数は以下の処理を行います。

  1. 指定された日付範囲を分割します(例えば、30日ごとに)。

  2. 各分割された日付範囲に対して水位データをスクレイピングします。

  3. 取得したデータをまとめ、指定されたファイル(ここでは`"combined_data.json"`)に保存します。

以下に、変数設定と関数呼び出しのコードを示します。

start_date = "20230701"
end_date = "20240712"
station_id = "302041282207240"  # 実際のステーションIDに置き換えてください
output_file = "combined_data.json"

# データをスクレイピングして保存
scrape_and_save_all_data(start_date, end_date, station_id, output_file)

このコードを実行することで、指定された期間とステーションIDに基づいて水位データを取得し、`combined_data.json`ファイルに保存することができます。

この記事が気に入ったらサポートをしてみませんか?