Pythonで水文水質データベースをスクレイピングしよう♪
Pythonを使用して水位データをスクレイピングし、JSONファイルとして保存する方法について説明します。このブログでは、以下の内容をカバーします。(責任は負いません)
ライブラリのインポート
水位データのスクレイピング
日付範囲の分割
データの保存
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ファイルとして保存するためのものです。
変数の説明
start_date
`start_date = "20230701"`
スクレイピングを開始する日付です。ここでは2023年7月1日からデータを取得します。
日付形式は`"YYYYMMDD"`です。
end_date
`end_date = "20240712"`
スクレイピングを終了する日付です。ここでは2024年7月12日までデータを取得します。
日付形式は`"YYYYMMDD"`です。
station_id
`station_id = "302041282207240"`
水位データを取得する特定のステーションのIDです。このIDは、各ステーション固有の識別子です。
実際に使用するステーションのIDに置き換える必要があります。
output_file
`output_file = "combined_data.json"`
取得したデータを保存するファイル名です。ここでは`"combined_data.json"`という名前のJSONファイルにデータを保存します。
ファイル形式はJSONです。
全体の流れ
この設定に基づいて、`scrape_and_save_all_data`関数を呼び出します。この関数は以下の処理を行います。
指定された日付範囲を分割します(例えば、30日ごとに)。
各分割された日付範囲に対して水位データをスクレイピングします。
取得したデータをまとめ、指定されたファイル(ここでは`"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`ファイルに保存することができます。