質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

3267閲覧

気象庁のスクレイピングにおいて、CSVにデータをうまく出力できない

humanbeing

総合スコア7

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/02/23 09:06

気象庁の気象データ、年ごとの値をスクレイピングしたい

こんにちは。

気象動向をスクレイピングで調査してみたいのですが、データをCSVにうまく出力できず、困っております。

プログラミング初心者なので、簡単なミスが原因かもしれません。

もし原因がわかる方がいらしゃいましたら、教えていただけますでしょうか。不慣れながら、Githubの方にもアップロードしています。もしよければお使いください。(うまくできていなかったら申し訳ないです)

https://github.com/yamaplay/weather-scraping

CSV自体はそれぞれの地域ごとに作成されるものの、webからデータを一切抽出できていない

エラーメッセージなどは表示されず、9つの(地域名).csvがそれぞれ生成されます。しかし、All_listの中身がカラムとして1行目に存在するだけで、実際のデータはcsvに出力されていない状態です。おそらく、スクレイピングそのものが実行されていないか、データの指定を間違えているのだと思います。エラーが表示されているわけでもなく、どのように対処したらよいのか行き詰っています。

ソースコード

place_name = ["札幌", "秋田", "新潟", "東京", "大阪", "広島", "高知", "熊本", "那覇"] place_codeA = [14, 32, 54, 44, 62, 67, 74, 86, 91] place_codeB = [47412, 47582, 47604, 47662, 47772, 47765, 47893, 47819, 47936] import requests from bs4 import BeautifulSoup import csv base_url = "http://www.data.jma.go.jp/obd/stats/etrn/view/annually_s.php?prec_no=%s&block_no=%s&year=2021&month=1&day=1&view=p1" def str2float(str): try: return float(str) except: return 0.0 if __name__ == "__main__": for place in place_name: All_list = [['年', '陸の平均気圧(hPa)', '海の平均気圧(hPa)', '降水量(mm)', '平均気温(℃)','最高気温(℃)', '最低気温(℃)', '平均湿度(%)']] print(place) index = place_name.index(place) r = requests.get(base_url%(place_codeA[index], place_codeB[index])) r.encoding = r.apparent_encoding soup = BeautifulSoup(r.text) rows = soup.findAll('tr',class_='mtx') rows = rows[3:] for row in rows: data = row.findAll('td') rowData = [] rowData.append(str(data[0].string)) rowData.append(str2float(data[1].string)) rowData.append(str2float(data[2].string)) rowData.append(str2float(data[3].string)) rowData.append(str2float(data[7].string)) rowData.append(str2float(data[10].string)) rowData.append(str2float(data[11].string)) rowData.append(str2float(data[12].string)) All_list.append(rowData) with open(place + '.csv', 'w') as file: writer = csv.writer(file, lineterminator='\n') writer.writerows(All_list)

補足、参考

参考にしているサイトは以下の通りです。
GoogleColaboratoryで気象庁の過去気象データをスクレイピングしてみた。
https://qiita.com/Cyber_Hacnosuke/items/122cec35d299c4d01f10
(このサイトのコード通りに実行してみましたが、そちらの方はうまくいきました。)

スクレイピングしたいサイト
http://www.data.jma.go.jp/obd/stats/etrn/view/annually_s.php?prec_no=44&block_no=47662&year=2021&month=1&day=1&view=p1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Pandas には read_html というメソッドがあって、HTML の table を取得してデータフレームに変換してくれます。それを利用すると以下の様に書くこともできます。参考にしてみて下さい。

python

1import pandas as pd 2 3places = [ 4 ['札幌', '秋田', '新潟', '東京', '大阪', '広島', '高知', '熊本', '那覇'], 5 [14, 32, 54, 44, 62, 67, 74, 86, 91], 6 [47412, 47582, 47604, 47662, 47772, 47765, 47893, 47819, 47936] 7] 8places = [{'name': n, 'codeA': a, 'codeB': b} for n, a, b in zip(*places)] 9columns = [ 10 '年', '陸の平均気圧(hPa)', '海の平均気圧(hPa)', '降水量(mm)', 11 '平均気温(℃)','最高気温(℃)', '最低気温(℃)', '平均湿度(%)'] 12col_idx = [0, 1, 2, 3, 7, 10, 11, 12] 13base_url = 'http://www.data.jma.go.jp/obd/stats/etrn/view/annually_s.php?prec_no={}&block_no={}&year=2021&month=1&day=1&view=p1' 14 15for place in places: 16 df = pd.read_html(base_url.format(place['codeA'], place['codeB']), 17 attrs={'id': 'tablefix1'}) 18 df = df[0].iloc[:, col_idx].fillna(0.0) 19 df.columns = columns 20 df.iloc[:, 1:] = df.iloc[:, 1:].apply( 21 lambda x: x.astype(str).str.replace(r'[^0-9.-]', '', regex=True) 22 .replace('', '0.0').astype(float)) 23 df.to_csv(f'{place["name"]}.csv', index=False)

bash

1$ ls -1sh *.csv 28.0K 熊本.csv 38.0K 広島.csv 48.0K 高知.csv 58.0K 札幌.csv 68.0K 秋田.csv 78.0K 新潟.csv 88.0K 大阪.csv 98.0K 東京.csv 108.0K 那覇.csv 11 12$ head 東京.csv 13年,陸の平均気圧(hPa),海の平均気圧(hPa),降水量(mm),平均気温(),最高気温(),最低気温(),平均湿度(%) 141875,0.0,0.0,1219.2,17.0,35.1,-3.6,0.0 151876,0.0,1014.7,1755.5,13.6,35.6,-9.2,78.0 161877,0.0,1015.2,1317.3,14.2,34.9,-4.8,77.0 171878,0.0,1015.2,1764.2,13.8,35.1,-7.6,79.0 181879,0.0,1014.5,1492.7,14.6,33.9,-5.5,77.0 191880,0.0,1015.0,1685.7,14.1,33.2,-6.8,76.0 201881,0.0,1015.1,1444.4,13.8,34.2,-8.4,78.0 211882,0.0,1015.2,1478.3,14.0,34.2,-6.3,77.0 221883,0.0,1015.0,1552.6,13.3,32.8,-7.8,76.0

投稿2022/02/23 12:46

melian

総合スコア19825

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humanbeing

2022/02/24 07:52

meilianさん、ありがとうございます。 read_htmlメソッドは全く知りませんでした。Pandasも奥が深いですね.... 少しコードは複雑そうですが、勉強がてら読み解いてみます。 ありがとうございます!
guest

0

参考情報

投稿2022/02/23 10:15

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humanbeing

2022/02/24 07:55

katoyさん、回答ありがとうございます。 いくつかスクレイピングのサイトは見ていたのですが、最も簡単そうに見えたものを参考にしていました。こちらでもclass指定が少し異なっているようなので、気を付けたいと思います。 ありがとうございます!
guest

0

ベストアンサー

rows = rows[3:]
サイトを見るとclass='mtx'がは3つしかないと思うのですが、4つ目以降を取得しようとしていることが原因ではないでしょうか?

参考サイトでは実際のデータもmtxに入っていますが、アップデートされてmtx2に入っているためクラスの指定をmtx2に変更する必要があると思います。

python

1place_name = ["札幌", "秋田", "新潟", "東京", "大阪", "広島", "高知", "熊本", "那覇"] 2 3place_codeA = [14, 32, 54, 44, 62, 67, 74, 86, 91] 4 5place_codeB = [47412, 47582, 47604, 47662, 47772, 47765, 47893, 47819, 47936] 6 7import requests 8from bs4 import BeautifulSoup 9import csv 10 11base_url = "http://www.data.jma.go.jp/obd/stats/etrn/view/annually_s.php?prec_no=%s&block_no=%s&year=2021&month=1&day=1&view=p1" 12 13def str2float(str): 14 try: 15 return float(str) 16 except: 17 return 0.0 18 19if __name__ == "__main__": 20 21 for place in place_name: 22 All_list = [['年', '陸の平均気圧(hPa)', '海の平均気圧(hPa)', '降水量(mm)', '平均気温(℃)','最高気温(℃)', '最低気温(℃)', '平均湿度(%)']] 23 print(place) 24 index = place_name.index(place) 25 26 r = requests.get(base_url%(place_codeA[index], place_codeB[index])) 27 r.encoding = r.apparent_encoding 28 29 soup = BeautifulSoup(r.text) 30 31 rows = soup.findAll('tr', class_='mtx2') 32 print(len(rows)) 33 # rows = rows[3:] 34 35 for row in rows: 36 data = row.findAll('td') 37 rowData = [] 38 rowData.append(str(data[0].string)) 39 rowData.append(str2float(data[1].string)) 40 rowData.append(str2float(data[2].string)) 41 rowData.append(str2float(data[3].string)) 42 rowData.append(str2float(data[7].string)) 43 rowData.append(str2float(data[10].string)) 44 rowData.append(str2float(data[11].string)) 45 rowData.append(str2float(data[12].string)) 46 All_list.append(rowData) 47 48 with open(place + '.csv', 'w') as file: 49 writer = csv.writer(file, lineterminator='\n') 50 writer.writerows(All_list) 51

投稿2022/02/23 10:10

編集2022/02/23 11:22
kyokio

総合スコア560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

humanbeing

2022/02/24 05:13

kyokioさん、回答ありがとうございます。 ご指摘の部分の確認を行った所、データの部分のclassが確かにmtx2でした。スクレイピング箇所のミスだったようですね。 コード付きの回答大変助かりました。ありがとうございます!
kyokio

2022/02/24 05:16

お役に立ててよかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問