ゴーストと天気予報と灯(akari.dll)のお話

 - by Don

気象庁の中の人より、非公式ながらAPIっぽいものが利用できるとの発信がありました。

天気予報といえば実に伺かっぽいです。天気予報の機能があるゴーストさんもそれなりに見受けられた気がします。しかしおそらく大体のゴーストはどこかのWebページをスクレイピングしていたのではないかと想像します。しかしこの非公式APIを利用できればもう少しまともな実装ができそうです。

JSONパーサSAORIを求めて

2021-03-22追記。黄桃の誄歌-Etu-様にて「YAYA as SAORI jsonパーサ」が公開されております。追記ここまで。

この非公式APIはJSON形式で出力しているようです。ゴーストから利用するにはJSONを解析したいところです。JSONが扱えるSAORIを探してみましたがなかなか見つかりません。しかしJSONを扱えるSHIORIを見つけました。

夜天燈火

灯(akari.dll)という名のSHIORIで、ドキュメントを見るに、辞書型の変数をサポートしているようです。そして_json2azvという内部関数を使えば辞書型や配列型の変数として読み込んでくれると。また_customrequest関数を独自に定義することでSAORIとして使用することも可能なようです。

ワクワクが止まりません。もはや天気予報などそっちのけでこのSHIORIへの興味が湧いてきました。

サンプルゴーストの639C 灯花さんの中身を見て構造を理解しようと思っていたら、サンプルとしてこんな機能が用意されていました。

akari-weather-forecast

気象庁のWebページをスクレイピングして天気予報してる…。運命に導かれたかのような錯覚に陥ります。

do-you-wanna-do-like-this

「こういうことがやりたいんでしょ?」と言われているような気分です。いや、当初はそうだったけど。今は興味の対象は貴女なのです。

しかも現在の気象庁のWebページは昔と構造が変わっており天気予報機能は正常に動いておりません。スクレイピングの宿命ですね。冒頭の非公式APIを読み取るように変更すれば動きそうです。

fix-bug-if-you-want-akari

ああ、そうか。何と素晴らしいサンプルゴーストなのでしょう。灯の使い方を指南してくれるばかりでなく、練習問題まで用意してくれていたのですね。やってやろうじゃないの。

ghost\master\res\util.azr を以下のように書き換えます。

// 地域を選択させるサクラスクリプトを返します。
string weather_news_arealist()
{
	string	strAreas;
	array	arKeys	=	_dickeyget( dictWeatherAreas );

	strAreas	+= "\_q";
	for( int i=0; arKeys[i]!=nil; i++ )
	{
		if( i%2 == 0 )	strAreas += "\n";
		strAreas	+= "\![*]\q["+arKeys[i]+",OnWeatherNewsAreaSelected,"+arKeys[i]+"]  ";
	}

	return strAreas;
}

// weather_news_arealist()によるサクラスクリプトから、地域を選択した時に呼ばれます。
OnWeatherNewsAreaSelected( dict ref )
{
	_create_thread( "TH_OnWeatherNewsAreaSelected", ref["Reference0"] );
}

// OnWeatherNewsAreaSelectedから別スレッドで起動される関数です。
// 天気予報を取得してキャラクターに喋らせます。
TH_OnWeatherNewsAreaSelected( string strArea )
{
	dict	dictWN	=	weather_news( strArea );
	
	string	strTalk	=	"\0\s[0]\b[2]"+strArea+"の天気は…\n";
	strTalk	+=	dictWN["text"];
	strTalk	+=	"\n\n(※出典:気象庁ホームページ)\e";

	_speak( strTalk );
}

/*
weather_news
・この関数の結果を使用するときは、「出典:気象庁ホームページ」を記載してください。
・引数であるstrAreaNameには転記を知りたい地域の名前を指定して下さい。
 指定できる地域の名前は、dictWeatherAreasという辞書型変数のキー値です。
・dictWeatherAreasはこの関数の後ろにグローバル変数として定義されています。
*/ 
dict weather_news( string strAreaName )
{
	string strAreaFileName = dictWeatherAreas[strAreaName];
	if( strAreaFileName == "" ) strAreaFileName = dictWeatherAreas["東京都"];
	
	array	arHtml = _httpget( "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/"+strAreaFileName+".json", "utf8" );
	dict	dictWeather;
	dictWeather = _json2azv(arHtml);
	
	return dictWeather;
}
	dict dictWeatherAreas = ${
		$("宗谷地方", "011000" ), $("上川・留萌地方", "012000" ),
		$("網走・北見・紋別地方", "013000" ), $("釧路・根室地方", "014100" ),
		$("胆振・日高地方", "015000" ), $("石狩・空知・後志地方", "016000" ),
		$("渡島・檜山地方", "017000" ), $("青森県", "020000" ),
		$("秋田県", "050000" ), $("岩手県", "030000" ),
		$("山形県", "060000" ), $("宮城県", "040000" ),
		$("福島県", "070000" ), $("茨城県", "080000" ),
		$("群馬県", "100000" ), $("栃木県", "090000" ),
		$("埼玉県", "110000" ), $("千葉県", "120000" ),
		$("東京都", "130000" ), $("神奈川県", "140000" ),
		$("山梨県", "190000" ), $("長野県", "200000" ),
		$("新潟県", "150000" ), $("富山県", "160000" ),
		$("石川県", "170000" ), $("福井県", "180000" ),
		$("静岡県", "220000" ), $("岐阜県", "210000" ),
		$("愛知県", "230000" ), $("三重県", "240000" ),
		$("大阪府", "270000" ), $("兵庫県", "280000" ),
		$("京都府", "260000" ), $("滋賀県", "250000" ),
		$("奈良県", "290000" ), $("和歌山県", "300000" ),
		$("島根県", "320000" ), $("広島県", "340000" ),
		$("鳥取県", "310000" ), $("岡山県", "330000" ),
		$("香川県", "370000" ), $("愛媛県", "380000" ),
		$("徳島県", "360000" ), $("高知県", "390000" ),
		$("山口県", "350000" ), $("福岡県", "400000" ),
		$("佐賀県", "410000" ), $("長崎県", "420000" ),
		$("熊本県", "430000" ), $("大分県", "440000" ),
		$("宮崎県", "450000" ), $("鹿児島県", "460100" ),
		$("沖縄本島地方", "471000" ), $("大東島地方", "472000" ),
		$("宮古島地方", "473000" ), $("八重山地方", "474000" )
	};

これで無事に天気予報ができるようになりました。

weather-forecast-fixed

改善点があるとすればdictWeatherAreasの内容もベタ書きするのでなく非公式APIからリストとして取得してくるのが良さそうですが、今回はここまで。習作としてsupplementのNARにしておきます。自分が書いたコード部分のライセンスはパブリックドメインです。

639C_tomoka_supplement.nar

参考

新しい気象庁サイトからJSONデータが取得できる件 | MindTech

No comments yet.