Skip to content

Instantly share code, notes, and snippets.

@aoirint
Last active September 12, 2017 07:35
Show Gist options
  • Save aoirint/01d2f9e34586d47a86d67e3135971658 to your computer and use it in GitHub Desktop.
Save aoirint/01d2f9e34586d47a86d67e3135971658 to your computer and use it in GitHub Desktop.
気象庁HPからPython, requests, BSで天気予報、週間天気予報を取得、適当に(再)整形して出力するスクリプト
import sys
import re
import requests
from bs4 import BeautifulSoup
def as_int(tpl):
ls = list(tpl)
for j in range(len(ls)):
if isinstance(ls[j], tuple):
ls[j] = tuple(as_int(ls[j]))
elif isinstance(ls[j], list):
ls[j] = list(as_int(ls[j]))
else:
ls[j] = int(ls[j])
return ls
def get_week_forecast(fukenNo=319):
url = 'http://www.jma.go.jp/jp/week/' + str(fukenNo) + '.html'
html = requests.get(url).text
# マークアップがおかしいので修正
html = html.replace('</form>\n<tr>', '</form>\n')
html = html.replace('<th colspan="2" class="normal">', '<tr><th colspan="2" class="normal">')
bs = BeautifulSoup(html, 'html.parser')
table = bs.find(id='infotablefont')
fuken = bs.find(class_='titleText').text.split(' ')[1]
caption = table.find('caption').text
updated = caption.split('\u3000')[0]
rows = table.find_all('tr')
dayRow = [(int(r.text[:-1]), r.text[-1:]) for r in rows[0].find_all('th')[1:8]]
rows = rows[1:]
region_count = len(rows) // 5
regions = []
for i in range(region_count):
batch = rows[5*i:5*i + 6]
region = {}
region['name'] = batch[0].find(class_='normal').text[:-1]
region['weather'] = [r.text[:-1] for r in batch[0].find_all('td')[0:7]]
region['rain'] = as_int([tuple(r.text.split('/')) for r in batch[1].find_all('td')[1:8]])
region['reliability'] = [r.text if r.text != u'/' else None for r in batch[2].find_all('td')[1:8]]
region['cityname'] = batch[3].find(class_='cityname').text
region['maxtemp'] = as_int([tuple(filter(None, re.split(r'\W+', r.text))) for r in batch[3].find_all('td')[1:]])
region['mintemp'] = as_int([tuple(filter(None, re.split(r'\W+', r.text))) for r in batch[4].find_all('td')[1:]])
regions.append(region)
return {
'fukenNo': fukenNo,
'fuken': fuken,
'caption': caption,
'updated': updated,
'source': url,
'day': dayRow,
'region': regions
}
def get_forecast(fukenNo=319):
url = 'http://www.jma.go.jp/jp/yoho/' + str(fukenNo) + '.html'
html = requests.get(url).text
bs = BeautifulSoup(html, 'html.parser')
table = bs.find(id='forecasttablefont')
fuken = bs.find(class_='titleText').text.split(' ')[1]
caption = table.find('caption').text
updated = caption.split('気象庁')[0]
rows = table.find_all('tr')
region_count = len(rows) // 20
regions = []
for i in range(region_count):
hi = 20*i
batch = rows[hi:hi+20]
region = {}
region['name'] = batch[0].find('th').text.strip()
batch = batch[1:]
days = []
for j in range(3):
# day head 1, 8, 15 -> 0, 7, 14
dhi = 7*j
day = {}
day['date'] = int(re.match('.*?(\d+)', batch[dhi].find('th', class_='weather').text.strip()[:-1]).group(1))
day['weather'] = batch[dhi].find('th', class_='weather').find('img')['alt']
day['info'] = batch[dhi].find('td', class_='info').text
if j != 2:
rain = []
for k in range(1, 5):
r = batch[dhi+k].find_all('td')
rain.append((r[0].text, int(r[1].text[:-1]) if r[1].text[:-1] != '--' else None))
day['rain'] = rain
if not 'cityname' in region:
region['cityname'] = batch[dhi+6].find('td', class_='city').text
s = batch[dhi+6].find('td', class_='min').text
if len(s) != 0:
day['mintemp'] = int(s.strip()[:-1])
s = batch[dhi+6].find('td', class_='max').text
if len(s) != 0:
day['maxtemp'] = int(s.strip()[:-1])
days.append(day)
region['day'] = days
regions.append(region)
abstract = bs.find('pre', class_='textframe').text
return {
'fuken': fuken,
'fukenNo': fukenNo,
'caption': caption,
'updated': updated,
'source': url,
'region': regions,
'abstract': abstract
}
# オプション
# -fn 地域コード(府県番号、気象庁ページのファイル名数値部)、指定しない場合319(東京)
# -fc 指定地域の天気予報を出力
# -abs 天気概況を出力(-fcと併用)
# -wc 指定地域の週間天気予報を出力
# -a 指定地域のすべての天気予報を出力、指定しない場合先頭の1つのみ
if __name__ == '__main__':
options = {
'fukenNo': 319,
'forecast': False,
'abstract': False,
'weekcast': False,
'all': False
}
for option in sys.argv[1:]:
if option[0] == '-':
k, v = option[1:].split('=') if '=' in option else (option[1:], True)
if k == 'fn':
k = 'fukenNo'
if k == 'fc':
k = 'forecast'
if k == 'abs':
k = 'abstract'
if k == 'wc':
k = 'weekcast'
if k == 'a':
k = 'all'
if k in ('fukenNo'):
v = int(v)
if k in ('forecast', 'abstract', 'weekcast', 'all'):
if not isinstance(v, bool):
v = v.lower()
v = v == '1' or v == 't' or v == 'true' or v == 'on'
options[k] = v
if not options['forecast'] and not options['weekcast']:
print('''オプション
-fn 地域コード(府県番号、気象庁ページのファイル名数値部)、指定しない場合319(東京)
-fc 指定地域の天気予報を出力
-abs 天気概況を出力(-fcと併用)
-wc 指定地域の週間天気予報を出力
-a 指定地域のすべての天気予報を出力、指定しない場合先頭の1つのみ''')
exit()
sources = []
if options['forecast']:
fc = get_forecast(options['fukenNo'])
sources.append(fc['source'])
print('天気予報 - ' + fc['fuken'] + '(' + str(fc['fukenNo']) + ') ' + fc['updated'])
for i in range(len(fc['region']) if options['all'] else 1):
region = fc['region'][i]
print('#', region['name'] + '(' + region['cityname'] + ')')
for j in range(len(region['day'])):
day = region['day'][j]
print(str(day['date']).ljust(2), end=' ')
print(day['weather'].ljust(6, ' '), end=' ')
if 'rain' in day:
ls = [str(r[1]) if r[1] != None else '--' for r in day['rain']]
print('/'.join(ls).ljust(11), end=' ')
else:
print(' '*11, end=' ')
print(str(day['mintemp']).ljust(2) if 'mintemp' in day else '--', end=' ')
print(str(day['maxtemp']).ljust(2) if 'maxtemp' in day else '--', end=' ')
print()
if options['abstract']:
print()
print(fc['abstract'])
if options['forecast'] and options['weekcast']:
print()
if options['weekcast']:
wf = get_week_forecast(options['fukenNo'])
sources.append(wf['source'])
print('週間天気予報 - ' + wf['fuken'] + '(' + str(wf['fukenNo']) + ') ' + wf['updated'])
for i in range(len(wf['region']) if options['all'] else 1):
region = wf['region'][i]
print('#', region['name'] + '(' + region['cityname'] + ')')
for j in range(len(wf['day'])):
print((str(wf['day'][j][0]) + '(' + wf['day'][j][1] + ')').ljust(5), end=' ')
print(region['weather'][j].ljust(4, ' '), end=' ')
l = len(region['rain'][j])
s = ''
for k in range(l):
s += str(region['rain'][j][k]) + ('/' if k != l-1 else '')
print(s.ljust(11), end=' ')
l = len(region['mintemp'][j])
s = str(region['mintemp'][j][0]) if l > 0 else ''
if l == 3:
s += '(' + str(region['mintemp'][j][1]) + '-' + str(region['mintemp'][j][2]) + ')'
print(s.ljust(9), end=' ')
l = len(region['maxtemp'][j])
s = str(region['maxtemp'][j][0]) if l > 0 else ''
if l == 3:
s += '(' + str(region['maxtemp'][j][1]) + '-' + str(region['maxtemp'][j][2]) + ')'
print(s.ljust(9))
print('-----')
print('このアプリケーションは、気象庁ホームページから取得したデータを加工表示しています')
print('ソース:' + ', '.join(sources))
@aoirint
Copy link
Author

aoirint commented Sep 12, 2017

$ python tenki.py -fn=319 -fc -abs -wc -a
天気予報 - 東京都(319) 12日11時
# 東京地方(東京)
12 雨後曇り     --/--/60/30 -- 28
13 晴れ時々曇り  10/0/10/10  -- 28
14 曇り時々晴れ  -- --
# 伊豆諸島北部(大島)
12 曇り一時雨   --/--/50/30 -- 28
13 曇り時々晴れ  20/20/10/10 -- 28
14 曇り時々晴れ  -- --
# 伊豆諸島南部(八丈島)
12 曇り         --/--/30/30 -- 29
13 曇り一時雨   50/50/30/20 -- 29
14 曇り時々晴れ  -- --
# 小笠原諸島(父島)
12 晴れ時々曇り  --/--/10/10 -- 31
13 晴れ時々曇り  10/10/10/10 -- 31
14 晴れ時々曇り  -- --

天気概況
平成29年9月12日10時41分 気象庁予報部発表

 日本海には前線を伴った低気圧があって、東北東へ進んでいます。
 
 【関東甲信地方】
 関東甲信地方は、雨や曇りで雷を伴って激しく降っている所があります。

 12日は、低気圧や前線の影響で曇りや雨となり、夕方まで雷を伴って非
常に激しく降る所があるでしょう。

 13日は、高気圧に覆われて、おおむね晴れる見込みです。

 関東近海では、12日は波が高く、13日はうねりを伴い波がやや高いで
しょう。船舶は高波に注意してください。

 【東京地方】
 12日は、雨で夕方まで雷を伴い、夜には曇りとなるでしょう。
 13日は、晴れで時々曇りとなる見込みです。

週間天気予報 - 東京都(319) 9月12日11時
# 東京地方(東京)
13(水) 晴時々曇  10/0/10/10  31       22
14(木) 曇時々晴  20          28/25/30 21/19/22
15(金) 晴時々曇  10          25/22/28 19/18/21
16(土) 曇時々晴  30          22/19/25 18/16/19
17(日) 曇一時雨 50          23/20/26 17/15/19
18(月) 曇一時雨 50          25/22/29 19/17/21
19(火) 曇時々晴  30          26/23/30 19/17/21
# 伊豆諸島(八丈島)
13(水) 曇一時雨 50/50/30/20 27       24
14(木) 曇時々晴  20          28/26/30 22/20/23
15(金) 曇時々晴  40          26/24/29 21/19/22
16(土) 曇一時雨 50          25/23/27 20/18/22
17(日) 曇一時雨 60          26/24/28 20/18/22
18(月) 曇一時雨 60          27/25/29 21/19/23
19(火) 曇       40          27/25/29 21/20/23
# 小笠原諸島(父島)
13(水) 晴時々曇  10/10/10/10 31       26
14(木) 晴時々曇  10          29/28/30 25/24/26
15(金) 晴時々曇  10          29/28/30 26/24/27
16(土) 晴時々曇  10          29/28/30 25/24/27
17(日) 晴時々曇  10          29/28/30 26/24/27
18(月) 晴時々曇  10          30/28/31 26/24/27
19(火) 曇時々晴  20          30/28/31 26/24/27
-----
このアプリケーションは、気象庁ホームページから取得したデータを加工表示しています
ソース:http://www.jma.go.jp/jp/yoho/319.html, http://www.jma.go.jp/jp/week/319.html

こんな感じ

@aoirint
Copy link
Author

aoirint commented Sep 12, 2017

$ python tenki.py
オプション
 -fn    地域コード(府県番号、気象庁ページのファイル名数値部)、指定しない場合319(東京)
 -fc    指定地域の天気予報を出力
 -abs   天気概況を出力(-fcと併用)
 -wc    指定地域の週間天気予報を出力
 -a     指定地域のすべての天気予報を出力、指定しない場合先頭の1つのみ

@aoirint
Copy link
Author

aoirint commented Sep 12, 2017

rev3

python tenki.py -fn=319 -fc -abs -wc -a
天気予報 - 東京都(319) 12日11時
# 東京地方(東京)
12 雨後曇り   --/--/60/30 -- 28
13 晴れ時々曇り 10/0/10/10  22 31
14 曇り時々晴れ             -- --
# 伊豆諸島北部(大島)
12 曇り一時雨  --/--/50/30 -- 28
13 曇り時々晴れ 20/20/10/10 24 29
14 曇り時々晴れ             -- --
# 伊豆諸島南部(八丈島)
12 曇り     --/--/30/30 -- 29
13 曇り一時雨  50/50/30/20 24 27
14 曇り時々晴れ             -- --
# 小笠原諸島(父島)
12 晴れ時々曇り --/--/10/10 -- 31
13 晴れ時々曇り 10/10/10/10 26 31
14 晴れ時々曇り             -- --

天気概況
平成29年9月12日10時41分 気象庁予報部発表

 日本海には前線を伴った低気圧があって、東北東へ進んでいます。
 
 【関東甲信地方】
 関東甲信地方は、雨や曇りで雷を伴って激しく降っている所があります。

 12日は、低気圧や前線の影響で曇りや雨となり、夕方まで雷を伴って非
常に激しく降る所があるでしょう。

 13日は、高気圧に覆われて、おおむね晴れる見込みです。

 関東近海では、12日は波が高く、13日はうねりを伴い波がやや高いで
しょう。船舶は高波に注意してください。

 【東京地方】
 12日は、雨で夕方まで雷を伴い、夜には曇りとなるでしょう。
 13日は、晴れで時々曇りとなる見込みです。

週間天気予報 - 東京都(319) 9月12日11時
# 東京地方(東京)
13(水) 晴時々曇 10/0/10/10  22        31
14(木) 曇時々晴 20          21(19-22) 28(25-30)
15(金) 晴時々曇 10          19(18-21) 25(22-28)
16(土) 曇時々晴 30          18(16-19) 22(19-25)
17(日) 曇一時雨 50          17(15-19) 23(20-26)
18(月) 曇一時雨 50          19(17-21) 25(22-29)
19(火) 曇時々晴 30          19(17-21) 26(23-30)
# 伊豆諸島(八丈島)
13(水) 曇一時雨 50/50/30/20 24        27
14(木) 曇時々晴 20          22(20-23) 28(26-30)
15(金) 曇時々晴 40          21(19-22) 26(24-29)
16(土) 曇一時雨 50          20(18-22) 25(23-27)
17(日) 曇一時雨 60          20(18-22) 26(24-28)
18(月) 曇一時雨 60          21(19-23) 27(25-29)
19(火) 曇    40          21(20-23) 27(25-29)
# 小笠原諸島(父島)
13(水) 晴時々曇 10/10/10/10 26        31
14(木) 晴時々曇 10          25(24-26) 29(28-30)
15(金) 晴時々曇 10          26(24-27) 29(28-30)
16(土) 晴時々曇 10          25(24-27) 29(28-30)
17(日) 晴時々曇 10          26(24-27) 29(28-30)
18(月) 晴時々曇 10          26(24-27) 30(28-31)
19(火) 曇時々晴 20          26(24-27) 30(28-31)
-----
このアプリケーションは、気象庁ホームページから取得したデータを加工表示しています
ソース:http://www.jma.go.jp/jp/yoho/319.html, http://www.jma.go.jp/jp/week/319.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment