やったこと
自己流の忘備録(書き途中)です。任意期間の河川の水質自動観測結果をPythonでスクレイピングし、csvとしてDL(手動だと7日間ごとしかできない)。エラー処理はまだ追加していない。それとcsvにヘッダーがない。改良する。
2019/9追記:あまり長い期間やるとはじかれる?ようです。2、3年くらいだとうまくいきましたが、5年だとだめでした。
流れ
http GETメソッドのパラメータ(取得したい地点、期間など)を設定し、リクエスト
↓
返ってきたhtmlをBeautifulSoupで解析し、必要な部分を抜き出す。
(html内のiframeという部分に、さらに別のURLでhtmlが参照されており、これが最終的な目的のデータとなる。)
↓
csvとして出力
コード
import csv
import time
from datetime import datetime
from datetime import timedelta
import requests
from bs4 import BeautifulSoup
#####↓関数を定義########################################################
#時間を、文字列←→日付型に相互に変換。どちらへ変換かは型で判別。
def time_tyconv(time):
if isinstance(time,str):return datetime.strptime(time,'%Y%m%d')
elif isinstance(time,datetime):return time.strftime("%Y%m%d")
else:raise TypeError('type-err!')
#日付からステップ数を算出。
#一回にスクレイピングする期間の限度が7日間。次のステップは8日後。
def step_number(start_date, end_date):
s = time_tyconv(start_date)
e = time_tyconv(end_date)
return int(((e-s).days + 1)//8)
#●日後の日付データを求める(start_dateの文字列をdatetime形式変換して7日足す→文字列に戻す)
def date_after_days(time,days):
day_after = time_tyconv(time) + timedelta(days=days)#ここは日付型
return time_tyconv(day_after)#ここで文字列になる。
#任意期間のデータを水水DBからスクレイピングする関数。
def scrp_DB(start_date, end_date, location_id,result_list):
base_url = 'http://www1.river.go.jp'
url = "http://www1.river.go.jp/cgi-bin/DspWquaData.exe"
params = {
"KIND":5,
"ID":location_id,
"BGNDATE":start_date,
"ENDDATE":end_date,
"KAWABOU":"NO"
}
#iframeのhtmlからsrcURLを取得
resp = requests.get(url,params=params)
temp_soup = BeautifulSoup(resp.text,'html.parser')
resp_iframe = requests.get(base_url+temp_soup.iframe['src'])
#srcURLのhtmlを取得
#テーブル内のデータは、iframeにある。iframeのデータは別のhtmlに記述されている。
#tableが2つあり、border = "●"で区別可能。border = "1"が目的の表。
soup = BeautifulSoup(resp_iframe.text,'html.parser')
soup = soup.select_one("table[border='1']")
tr_list = soup.find_all("tr")
tr_list.pop(0)
#ヘッダー分をpop(0)で削除。
for tr in tr_list:
result_row = []
td_list = tr.find_all('td')
for td in td_list:
cell = td.get_text()
result_row.append(cell)
result_list.append(result_row)
return result_list
#######↓メインの流れ###################################################
#取得期間、地点番号(おそらく4から始まるほう)、保存ファイル名を設定
start_date = "20171201"
end_date = "20181031"
csvfile_name = "result_johoku.csv"
location_id = "403021283322090"
n_step = step_number(start_date, end_date)
result_list = []
#8の倍数回scrp_DBを実行
for n in range(n_step):
result_list = scrp_DB(start_date, date_after_days(start_date,7), location_id,result_list)
#start_dateに8日足して、次のループへ
start_date = date_after_days(start_date,8)
time.sleep(2)#サーバーへの負荷を考慮し、2秒置く
#8の倍数で余った期間でscrp_DBを実行
result = scrp_DB(start_date, end_date,location_id,result_list)
#CSVとして出力
with open(csvfile_name, 'w') as file:
writer = csv.writer(file, lineterminator='\n')
writer.writerows(result)
つまづいたところ
htmlのiframe(インラインフレーム)のデータ取得
htmlの中のiframeの中にさらにhtmlが参照されていて、こちらのURL(上記コードのsrcURL)を探してくる必要がある。WEBブラウザの開発ツールでiframeを覗くと、src属性?にURLが書いてあり、ベース?のURLにくっつけて目的のhtmlを取得する。
tableのデータ取得
クジラ飛行机さんの本にちょうどtableのtr,tdを取得するやり方が載っていたので参考にしました。
日付
文字列型←→日付型が混乱した。今後自分用に追記もしくは別でまとめる。
#参考
- クジラ飛行机さんの本(スクレイピングのやつ)
http://www.socym.co.jp/book/1079