PHP
XML
nhk
地震

NHKの地震情報を掻っ攫う方法

2019年4月5日 追記 : NHKの災害情報ページがリニューアルしていましたが、APIの変更は無いみたいなのでリンクだけ修正しました。

この方法はNHKが公式に発表しているものでもなければ、この記事に書かれていることを行ったことによる損害を筆者が負うものでもありません!

NHKがお家を訪問してきたり、NHKニュースを読むことができなくなるかもしれません!


NHKの地震情報(震度マップ)を取得したい

地震駆動型プログラマの筆者は、5月25日21時13分ごろに発生した長野県で震度5強を観測する地震を受け、NHKの地震情報をどうにかして手に入れられないか? と悩んでいました。

情報元 : NHK あなたの天気・防災|地震情報

最初は任意の言語でWebスクレイピングすればいいかなとか考えていましたが、開発者ツールで覗いてみると「どうぞ再利用してください」と言わんばかりの非常に簡単な実装がされていました。


スクレイピングを試す(試してない)

手始めに情報元のHTMLソースを覗いてみると、すでにデータが入力されているわけでなく、後からデータを引っ張ってくる非同期式の方法をとっていました。

この場合、スクレイピングの実装が複雑になってしまいます。

しかし、非同期式のためどこかのJavaScriptでデータを読みに行っている可能性が非常に高いのではないかと勘付きました。


開発者ツールのネットワークタブを確認する

最初、私は「震度マップ」のみを取ることができれば良い、と考えていましたが、まとめてデータが取れることに後々気づきました。

ウォーターファールを見ているとそれっぽいファイルが……

image.png

試しに、JishinReport.xmlを覗いてみると以下のXMLソースが取れました。


JishinReport.xml


JishinReport.xml


<jishinReport>
<record date="2018年05月25日">
<item time="21時28分ごろ" shindo="2" url="https://www3.nhk.or.jp/sokuho/jishin/data/JSA0180525212844_20180525213138.xml">長野県北部</item>
</record>
<record date="2018年05月23日">
<item time="14時04分ごろ" shindo="1" url="https://www3.nhk.or.jp/sokuho/jishin/data/JSA0180523140446_20180523140848.xml">父島近海</item>
</record>



<record date="2018年05月19日">
<item time="17時35分ごろ" shindo="1" url="https://www3.nhk.or.jp/sokuho/jishin/data/JSA0180519173518_20180519173825.xml">北海道北西沖</item>
<item time="08時50分ごろ" shindo="1" url="https://www3.nhk.or.jp/sokuho/jishin/data/JSA0180519085005_20180519085308.xml">山梨県東部・富士五湖</item>
</record>
</jishinReport>


また、パラメータとしてtがあり、UNIXタイムスタンプかな?と変換ツールにかけてみたのですが現時刻とは明らかにかけ離れている日時を示したため、何か別の時刻表記を使用しているのかもしれません。

これは要研究。

なお、パラメータtを付与しないことによるエラーは発生しない模様。

むしろ、最新の情報を返してくれる。


JishinReport.xmlの構造

要素名
説明
親要素
含まれる数
属性

jishinReport
ルート要素
-
1
-

record
日付
jishinReport
変動

data : 日付(Y年m月d日)

item
各地震
record
変動

time : 時間(H時i分ごろ)
shindo : 最大震度
url : 地震の詳細情報XML URL

すごくシンプル!!!

しかも、itemの属性urlから地震情報が取れる! つよい!


JishinReport.xmlのitem[url]から詳細情報を取得する


詳細情報XML


JSA0180525220014_20180525220427.xml

<Root>

<Timestamp>2018/05/25 22:04:27</Timestamp>
<Earthquake Id="A0180525220014" Time="2018/05/25 22:01:00" Intensity="1" Epicenter="長野県北部" Latitude="北緯 36.9度" Longitude="東経 138.6度" Magnitude="2.2" Depth="10km">
<Detail>data/JS00cwA0180525220014_20180525220427.jpg</Detail>
<Local>data/JS00cuA0180525220014_20180525220427.jpg</Local>
<Global>data/JS00clA0180525220014_20180525220427.jpg</Global>
<Relative>
<Group Intensity="1">
<Area Name="栄村"/>
</Group>
</Relative>
</Earthquake>
</Root>


詳細情報XMLの構造

要素名
説明
親要素
含まれる数
属性

Root
ルート要素
-
1
-

Timestamp
情報発表日時(Y/m/d H:i:s)
Root
1
-

Earthquake
地震データ
Root
1

Id : 地震ID?
Time : 地震発生日時(Y/m/d H:i:s)
Intensity : 最大震度
Epicenter : 震源地
Latitude : 緯度(北緯 xx.x度)
Longitude : 経度(東経 xxx.x度)
Magnitude : マグニチュード
Depth : 震源の深さ

Detail
震度マップ(概況)
Earthquake
1

Local
震度マップ(拡大)
Earthquake
1

Global
震度マップ(広域)
Earthquake
1

Relative
各地の震度
Earthquake
1

Group
同じ震度の集合
Relative
変動

Intensity : 震度(○弱は○-,○強は○+)

Area
地名(要素のみ)
Group
変動

Name : 地名

すごい!! 直感的!!

もっと複雑なものかと思ったら、意外にもシンプルでした。


最新の震度マップ及び諸々の情報をまとめるページを作る

これこそ、情報元でも十分なのですが再利用したいという気持ちは変わらないので、PHPを用い画像と情報を引っ張って表示するサンプルプログラムを書きます。


サンプルコード


nhk.php

<?php

/* NHKの地震情報をゴニョゴニョして貰う方法 by nirot1r */

$imageBaseURL = "http://www3.nhk.or.jp/sokuho/jishin/"; /* 1 */

$rawReportXML = mb_convert_encoding(file_get_contents("http://www3.nhk.or.jp/sokuho/jishin/data/JishinReport.xml"), "UTF-8", "SJIS"); /* 2 */

/* 3 */
$dump = explode("\n", $rawReportXML, 2);
$rawReportXML = '<?xml version="1.0" encoding="UTF-8" ?>' . $dump[1];
$xmlData = new SimpleXMLElement($rawReportXML);

$latestItemURL = $xmlData->record[0]->item[0]["url"]; /* 4 */

$rawLatestEarthquake = mb_convert_encoding(file_get_contents($latestItemURL), "UTF-8", "SJIS"); /* 5 */;

/* 3 */
$dump = explode("\n", $rawLatestEarthquake, 2);
$rawLatestEarthquake = '<?xml version="1.0" encoding="UTF-8" ?>' . $dump[1];
$earthquakeXMLData = new SimpleXMLElement($rawLatestEarthquake);

$earthquake = $earthquakeXMLData->Earthquake; /* 6 */
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1;">
<title>NHKの地震情報をゴニョゴニョして貰う方法 by nirot1r</title>
</head>
<body>

<h1><?= $earthquake["Time"] ?>に発生した地震</h1>
<p>
震源 : <?= $earthquake["Epicenter"] ?><br />
震源の深さ : <?= $earthquake["Depth"] ?><br />
マグニチュード : <?= $earthquake["Magnitude"] ?><br />
最大震度 : <?= $earthquake["Intensity"] ?>
</p>

<h2>震度マップ(概況)</h2>
<img src="<?= $imageBaseURL . $earthquake->Detail ?>" />

<h2>震度マップ(拡大)</h2>
<img src="<?= $imageBaseURL . $earthquake->Local ?>" />

<h2>震度マップ(広域)</h2>
<img src="<?= $imageBaseURL . $earthquake->Global ?>" />

</body>
</html>


デモ(中身のコードはほとんど同じ)

キャッシュなどの処理は実装していませんので、大量のアクセスは控えるように!


コード解説


1 : 画像ベースURL代入

震度マップのベースURLを代入します。


2 : 地震情報リスト取得

NHKから地震情報リストを取得します。

この時にShift-JISからUTF-8にエンコード変換しておきます。


3 : エンコード変更

2で受信したXMLはShift-JISのためSimpleXMLで処理することができません。

そこで、XMLのエンコード宣言部分を書き換え、SimpleXMLで扱えるようにします。


4 : 詳細情報XML URL取得

各オブジェクトの先頭(0)にある要素のURLを取得します。


5 : 詳細情報取得

4で取得したURLを基に、NHKにリクエストを行います。

2と同様、エンコード変換を行います。


6 : 地震オブジェクトを作成

地震情報へアクセスしやすいように、地震オブジェクトを作成します。


おわり

あとは、$earthquakeから必要な情報を取りだして終了です。


実行結果

image.png

image.png

image.png


まとめ

本当に開発者ファーストかと思うぐらい簡単に取得できました。

ただ、Shift-JISであることだけが注意点です。それ以外は非常によくまとまっていたと思います。

最後にも書きますが、試す際は自己責任でお願いします。

その他、「こうしたほうがいいよー!」「誤字あるじゃん」などありましたらコメント・編集リクエストでどうぞ!