LoginSignup
12
6

More than 1 year has passed since last update.

緯度・経度からWeb APIを利用して様々な情報を取得する

Last updated at Posted at 2021-12-01

##はじめに
本記事はMAヒーローズ・リーグ Advent Calendar 2021の12/4の記事となります。

今年も親子でヒーローズリーグ2021に参加しました。作成した作品は「toio地球儀」というもので、toioを2台用いた地球儀型の緯度経度入出力デバイスです。toio地球儀自体に興味がある方は、次の記事を確認して頂ければと思います。

image.pngtoio地球儀

本記事では、この「toio地球儀」を利用した1アプリケーションである「Scope」に着目し、どのようにWeb APIを利用し、緯度・経度から有益な情報を取得したかを記載します。ただし、本親子はWeb技術を勉強し始めてからまだ1年足らずですので、記載しているコード上は技術的に稚拙な点があるかと思います。その点はご容赦ください。

##地球ブラウザ「Scope」とは
地球ブラウザ「Scope」とは、toio地球儀と連携し、ユーザが入力した地球上の位置情報から、その位置に関連する情報をWebブラウザに表示するアプリケーションです。全部で8つのWeb APIを利用しており、位置情報(緯度・経度)から得られる思いつく限りの情報を1画面にまとめて提示します。開発時のコンセプトは「神様が人の暮らしを覗き込むときに利用する道具」でした。

image.png神様が人の暮らしを覗き込むときに利用する道具(イメージ)

「Scope」は、気になる場所をクリックすると、その場所に関する情報を手軽に確認することができる、暇つぶしにはちょうどよいアプリです。本来はtoio地球儀で緯度・経度を入力して利用することを想定したアプリではありますが、マウス操作にも対応し、一般利用できるようにしたものが↓です。画面左下にある地図をクリックすると、その場所に虫眼鏡マークが付き、その場所に関連する情報が表示されます。虫眼鏡のそばに表示されるカメラマークは、Webカメラ画像を取得した場所を表しています。

See the Pen sample2 by sunagimo (@sunagimo2) on CodePen.

このScopeで表示している情報と、そのときに利用しているWeb APIは次の通りです。

setumei9.png

以後、この緯度・経度情報から各種情報への変換に関し、実例を用いて説明します。

##緯度・経度から各種情報へ変換する8種類の事例

###1. Google Geocodingによる地名情報の取得
Google Geocodingを用いると、緯度経度情報から、その場所の地名情報を取得することが可能です。下の例は、(36.8, 137.9)の緯度経度情報から取得した地名情報です。

image.png

本機能を利用するには、Google Cloud Platform で Geocoding API を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。この手順に関しては、各種記事がありますので参考にするとよいと思います。

image.png

Geocoding API の API Key が取得できましたら、次のようなコードにより緯度経度(変数ichi)から地名情報を取得します。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
	<script src="https://maps.googleapis.com/maps/api/js?key=[取得したAPIキー]&libraries=&v=weekly"
		defer></script>
</head>

<body>
	<script>
		// 取得する緯度経度情報
		let ichi = {
			lat: 36.8,
			lng: 137.9
		};

		let geocoder;

		// ページの最初
		$(document).ready(function () {
			// Geocoder の生成
			geocoder = new google.maps.Geocoder();

			// 緯度経度情報から地名の取得
			geocoder.geocode({ 'location': ichi }, function (results, status) {
				if (status == 'OK') {
					console.log(results);
				}
			});
		});
	</script>
</body>

</html>

resultsの中に地名情報が格納されており、基本的にはresults[0]の中のaddress_componentsを辿っていけば、住所がすべて取得できます。また、address_componentsのtypesにcontryが含まれるものは国名を示しており、その時のshort_nameが「Country codes」となります。このContry codesは他のWeb API の入力値として必要になりますので、取得できた場合は変数に保存しましょう。

例えば、上のコードを実行した場合は、次のような結果が取得できます。この場合、results[0].address_components[4].short_name がその緯度経度のCountry codesです。

image.png

###2. Azure Maps Weatherによる現在の気象情報の取得

Azure Maps Weather を利用すると、緯度経度情報から、その場所の気象情報を取得することが可能です。下の例は、(36.8, 137.9)の緯度経度情報から取得した気象情報です。

image.png

本機能を利用するには、Microsoft Azure で Azure Maps を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。

image.png

API Key が取得できましたら、次のようなコードにより気象情報を取得します。関数引数のlatとlngには、それぞれ緯度、経度を数値で入力します。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
</head>

<body>
	<script>
		// Microsoft Azure で取得した API Key
		let AzureMapKey = [取得したAPIキー];

		// 取得する緯度経度情報
		let ichi = {
			lat: 36.8,
			lng: 137.9
		};

		// ページの最初
		$(document).ready(function () {
			update_weather(ichi.lat, ichi.lng);
		});

		// 現在位置の天気情報を取得
		function update_weather(lat, lng) {
			$.ajax({
				url: 'https://atlas.microsoft.com/weather/currentConditions/json?api-version=1.0&language=ja-JP&subscription-key='
					+ AzureMapKey + '&query=' + lat.toString() + ',' + lng.toString(),
				type: 'GET',
			}).then(
				function (results) {
					console.log(results);
				},
				function () {
					console.log("error");
				}
			);
		}
	</script>
</body>

</html>

成功すると、次のような結果が取得できます。results[0] の中を辿っていけば、ほしい情報が得られるはずです。なお、海の上など、気象情報が提供されていない地域に関しては、本関数が失敗を返すことが結構あります。エラー対策はしっかり行っておきましょう。

image.png

###3. Google Street Viewによる街並み画像の取得

Google Street View を利用すると、緯度経度の街並み画像(Street view)を取得することができ、マウス操作で街並み画像の拡大縮小、向きの変更などができるようになります。下の例は、(36.8, 137.9)の緯度経度情報から取得した街並み画像です。

image.png

本機能を利用するには、Google Cloud Platform で Maps JavaScript API を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。上で記載した Geocoding API でAPI Key を生成している場合、そのKeyの利用範囲に本APIも含めておくと、一つのKeyで両方とも利用することが可能です。

なお、Street View Static API という、もっとぴったりの名前のAPIもありますが、そちらはマウス操作に対応していません。

image.png

API Key が取得できましたら、次のようなコードで街並み画像を取得します。なお、街並み画像を表示する領域用に、panorama_areaをidとして持つ領域が定義されているものとします。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
	<script src="https://maps.googleapis.com/maps/api/js?key=[取得したAPIキー]&libraries=&v=weekly"
		defer></script>
</head>

<body>

	<div id="panorama_area" style="width:200pt; height:200pt;"></div>

	<script>
		// 取得する緯度経度情報
		let ichi = {
			lat: 36.8,
			lng: 137.9
		};

		let panorama;
		let StreetViewService;
		let search_radius = 5000; // 5km

		// ページの最初
		$(document).ready(function () {
			// Street View の定義
			panorama = new google.maps.StreetViewPanorama(
				document.getElementById("panorama_area"),
				{
					linksControl: false,
					panControl: false,
					zoomControl: false,
					addressControl: false,
					clickToGo: false,
					imageDateControl: false,
					showRoadLabels: false,
					panControl: false,
					zoom: 0,
				}
			);

			// StreetViewService
			StreetViewService = new google.maps.StreetViewService();
			update_panorama(ichi.lat, ichi.lng);
		});

		// 指定した緯度経度の半径5km内にある街並み画像を取得
		function update_panorama(lat, lng) {
			search_lating = new google.maps.LatLng(lat, lng);
			StreetViewService.getPanorama({ location: search_lating, preference: 'nearest', radius: search_radius }, check_street_view_pos).catch(errObj => {
				//例外を捕まえる必要がある。
			});
		}

		// 結果取得時のコールバック関数
		function check_street_view_pos(data, status) {
			if (status === "OK") {
				// 街並み画像が見つかったので、その画像を表示
				panorama.setPosition(data.location.latLng);
			} else {
				// 街並み画像が見つからなかった
			}
		}
	</script>
</body>

</html>

緯度経度からの街並み画像の表示は、街並み画像の取得と、表示に分けて実行します。街並み画像の取得には、StreetViewService を利用し、指定した緯度経度に最も近い街並み画像のある地点を検索します。このとき、検索範囲をm単位で取得することが可能です。日本では、数kmの検索範囲を設定すれば、まず街並み画像は見つかりますが、海外ではかなり範囲を広くしないと画像が取得できな場合があります。

街並み画像が見つかった場合、StreetViewPanoramaを利用し、その位置の街並み画像を画面に表示します。

###4. Google Mapsによる周辺地図の取得

有名なGoogle Maps を利用すると、緯度経度の周辺地図を表示することができます。下の例は、(36.8, 137.9)の緯度経度情報から取得した周辺地図画像です。

image.png

この機能も、「Google Street Viewによる街並み画像の取得」同様、Maps JavaScript API を有効にすることで利用可能です。次のようなコードで街並み画像を取得します。なお、周辺地図画像を表示する領域用に、map_areaをidとして持つ領域が定義されているものとします。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
	<script src="https://maps.googleapis.com/maps/api/js?key=[取得したAPIキー]&libraries=&v=weekly"
		defer></script>
</head>

<body>

	<div id="map_area" style="width:200pt; height:200pt;"></div>

	<script>
		// 取得する緯度経度情報
		let ichi = {
			lat: 36.8,
			lng: 137.9
		};

		let map;

		// ページの最初
		$(document).ready(function () {
			// Map の定義
			map = new google.maps.Map(
				document.getElementById("map_area"),
				{
					// 周辺地図表示時のオプション
					zoom: 2,
					clickableIcons: false,
					fullscreenControl: false,
					mapTypeControl: false,
					streetViewControl: false,
					zoomControl: false,
					draggable: true,
				});

			update_map(ichi.lat, ichi.lng);
		});

		// 指定した緯度経度を中心とする地図を表示する
		function update_map(lat, lng) {
			lating = new google.maps.LatLng(lat, lng);
			map.setCenter(lating);
		}
	</script>
</body>

</html>

周辺地図には、フキダシアイコンや画像などを配置することも可能です。

###5. Windy Webcamsによる近隣のWebカメラ画像の取得

Windy Webcams を利用すると、特定の緯度経度の近くに配置されたWebカメラから画像を取得することができます。下の例は、(36.8, 137.9)の緯度経度情報から取得したWebカメラ画像です。

image.png

本機能を利用するには、Windy のサイトで Webcams API を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。趣味で利用する範囲であれば、無料枠で行けると思います。

image.png

API Keyが取得できたら、次のコードでWebカメラ画像を取得できます。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
</head>

<body>

	<img id="windy" style="width:400pt; height:200pt;"></img>

	<script>
		// 取得する緯度経度情報
		let ichi = {
			lat: 36.8,
			lng: 137.9
		};

		// ページの最初
		$(document).ready(function () {
			update_windy(ichi.lat, ichi.lng);
		});

		// 緯度経度(lat, lng)に最も近いWebカメラ画像の取得
		function update_windy(lat, lng) {
			$.ajax({
				url: 'https://api.windy.com/api/webcams/v2/list/orderby=distance/nearby=' + lat.toString() + ',' + lng.toString() +
					',10000/limit=1?show=webcams:image,location',
				type: 'GET',
				headers: {
					'x-windy-key': [取得したAPIキー],
				},
			}).then(
				function (result) {
					if (result.result.webcams.length != 0) {
						console.log(result);

						// カメラ画像
						document.getElementById("windy").src = result.result.webcams[0].image.current.preview;
					}
					else {
						console.log("no camera");
					}
				},
				function () {
				}
			);
		}
	</script>
</body>

</html>

上のコードを実行すると、次のような結果が帰って来ます。result.result.webcams[0].image.current.preview を img のsrcに設定すれば、その画像を表示することが可能です。

image.png

###6. YouTube Data APIによるその地域の急上昇動画の取得

YouTube Data API を利用すると、その国のYouTube 急上昇動画を取得することができます。下の例は、2021/11/28時点の日本国の急上昇動画です。Google がどのようなアルゴリズムで急上昇動画を選定しているかはわかりませんが、一応、その時点で最も着目すべきYouTube動画ではあるようです。

image.png

本機能を利用するには、Google Cloud Platform で YouTube Data API V3 を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。上の Geocoding API ですでにAPI Key を生成している場合、そのKeyの利用範囲に、本APIも含めておくと、一つのKeyで利用法とも利用することが可能です。

image.png

API Keyが取得できたら、次のコードでその国の急上昇動画を取得できます。なお、引数として入力する国名は上記Google Geocoding API で取得したアルファベット2文字の「Country codes」が必要です。例えば日本では "JP"、アメリカでは "US"です。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
</head>

<body>
	<script>
		let GoogleKey = [APIキー情報]; // Google から取得した API Key

		// ページの最初
		$(document).ready(function () {
			update_youtube("JP");
		});

		// 引数で指定した国の急上昇動画を取得
		function update_youtube(CountryCodes) {
			$.ajax({
				url: 'https://www.googleapis.com/youtube/v3/videos?key=' + GoogleKey +
					'&chart=mostPopular&maxResults=1&regionCode=' + CountryCodes,
				dataType: 'json',
			}).then(
				function (result) {
					// この国の現時点での急上昇動画のID
					console.log(result.items[0].id);
				},
				function () {
					console.log("err");
				}
			);
		}
	</script>
</body>

</html>

動画のIDが取得できてしまえば、iframe埋め込みでの動画プレーヤーでの動画再生が可能となります。当然、YouTubeが浸透していない国では、上記スクリプトはエラーとなりますのでご注意ください。

###7. Bing News Searchによる地域のニュースの取得

Bing News Searchを用いると、指定した国のトップニュースを取得することが可能です。下の例は、2021/11/28 17:30時点での日本国のトップニュースです。例のコロナウィルスに「オミクロン」なんて可愛い名前が付いたのですね。

image.png

本機能利用には、Microsoft Azure で Bing News Search を有効にし、本APIを利用するためのAPI Keyを取得しておく必要があります。

image.png

API Keyが取得できたら、次のコードでその国のトップニュース情報が取得できます。なお、引数として入力する国名は上記Google Geocoding API で取得したアルファベット2文字の「Country codes」が必要です。例えば日本では "JP"、アメリカでは "US"です。このコードでは"news1_img" "news2_img"をIDとして持つニュースのサムネイル画像配置用のimgタグと、"news1_text" "news2_text" をIDとして持つニュースタイトル配置用のdivタグがあることを想定しています。

<!DOCTYPE html>
<html lang="ja">

<head>
	<script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
</head>

<body>

	<img id="news1_img" style="width:100pt; height:100pt;"></img>
	<p id="news1_text" style="width:100pt; height:100pt;"></p>

	<script>
		let api_key = [APIキー情報];

		// ページの最初
		$(document).ready(function () {
			update_news("JP");
		});

		// 引数で指定した国のニューストピックを取得し、Viewに反映
		function update_news(CountryCodes) {
			$.ajax({
				url: 'https://api.bing.microsoft.com/v7.0/news/search?count=2&cc=' + CountryCodes,
				type: 'GET',
				headers: {
					'Ocp-Apim-Subscription-Key': api_key,
					'Accept-Language': 'Jp',
				},
			}).then(
				function (result) {
					if (result.value[0].image) {
						// サムネネイルがない場合があるので注意
						document.getElementById("news1_img").src = result.value[0].image.thumbnail.contentUrl;
					}
					document.getElementById("news1_text").innerText = result.value[0].name;
				},
				function () {
				}
			);
		}
	</script>
</body>

</html>

###8. Spotify Web APIによる地域のヒットソングの再生
地域のヒットソングを再生するには、「地域のヒットソングの取得」と「取得した楽曲の再生」を行う必要があります。まず、地域のヒットソングを取得するには、Spotify Charts にアクセスし、楽曲のURLを取得する必要がありました。当初は、これもWeb APIで取得したかったのですが、どうしてもその手法がわかりませんでした。そのため、上記サイトを1日に一度巡回し、各国のヒットソングのURLを取得するようにしました。

地域のヒットソングは、ページ毎に分かれて管理されており、日本のヒットソングはこのページに格納されています。他の国のヒットソングを取得した場合は、URL の JP 部分にGoogle Geocodingで取得したCountry codesを入れて見てください。本記事執筆時点では、68の国と地域のヒットソングが取得できています。

このSpotify のサイトは、各楽曲を次のようなフォーマットで管理しています。

image.png

このサイトから、1位だけの情報を取得したいのであれば、次のようなXPathでデータを取り出すことが可能です。

// 楽曲へのリンク
var link = xmlDoc.evaluate("//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[1]/a/@href", xmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// 楽曲のサムネイル画像
var img = xmlDoc.evaluate("//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[1]/a/img/@src", xmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// アーティスト名
var artist = xmlDoc.evaluate("//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[4]/strong/text()", xmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// 曲名
var title = xmlDoc.evaluate("//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[4]/span/text()", xmlDoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

例えば、次のようなスクリプトを作成し、cronで定期的に実行することで、楽曲情報を取得できます。

#!/bin/bash

STR1="https://spotifycharts.com/regional/"
STR2="/daily/latest"

function startfile() {
  echo "let ranking = [" >ranking.js
}

function endfile() {
  echo "];" >>ranking.js
}

function getinfo() {
  curl --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.48 Safari/537.36" \
    -o tmp $STR1$1$STR2

  echo -n "	[\"" >>ranking.js
  echo -n $1 | tr '[:lower:]' '[:upper:]' >>ranking.js
  echo -n "\", \"" >>ranking.js
  xmllint --html --xpath "//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[4]/span/text()" tmp | sed -e "s/\"//g" >>ranking.js
  echo -n "\", \"" >>ranking.js
  xmllint --html --xpath "//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[4]/strong/text()" tmp | sed -e "s/\"//g" >>ranking.js
  echo -n "\", \"" >>ranking.js
  xmllint --html --xpath "//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[1]/a/@href" tmp | sed -e "s/ href=\"\([^\"]*\)\"/\1/g" |
    sed -e "s/^.\{31\}//" >>ranking.js
  echo -n "\", \"" >>ranking.js
  echo -n $STR1$1$STR2 >>ranking.js
  echo -n "\", \"" >>ranking.js
  xmllint --html --xpath "//*[@id='content']/div/div/div/span/table/tbody/tr[1]/td[1]/a/img/@src" tmp | sed -e "s/ src=\"\([^\"]*\)\"/\1/g" >>ranking.js
  echo "\"]," >>ranking.js
}

startfile
getinfo jp >/dev/null 2>&1
getinfo us >/dev/null 2>&1
endfile

Web API を利用した楽曲の再生には、Spotify Premium への入会が必要です。最初この制約がわからず、API呼び出しがエラーとなる現象に悩みましたが、Spotify Premium への入会によりエラーが発生しなくなりました。なお、2022年1月時点でSpotify Premium を退会したところ、再度エラーが出るようになりましたので、間違いないと思います。

Spotify Premium への入会したユーザは、Spotify Web APIを用いることでWeb APIを利用した楽曲再生が実現できます。まず、Spotify for Developersにアクセスし、Client ID と Client Secret を取得します。そして、Authorization Code Flow に従い、access_token と refresh_token を取得します。

image.png

下記のコードは、CountryCodesで国情報を指定すると、その国のヒットソングを再生するコードとなります。ちょっとややこしいですが、定期的にrefresh_spotifyを呼び出し、access_token をリフレッシュする必要があります。そして、そのaccess_token を用い、楽曲の再生を行います。再生されるデバイスは、現在のSpotify楽曲を再生しているデバイスですので、再生したいデバイスで事前に何らかの楽曲を再生しておくとよいでしょう。ranking 部分は上で説明した「地域のヒットソングの取得」により、日々更新されているものとします。

let access_token = [access_token];
let refresh_token = [refresh_token];
let authorization_basic = ["Client ID:Client Secret"をbase64化したもの];

// 一定時間ごとに呼び出し、spotify_token を更新する
function refresh_spotify() {
	$.ajax({
		url: 'https://accounts.spotify.com/api/token',
		type: 'POST',
		headers: {
			'Authorization': 'Basic ' + authorization_basic,
		},
		data: {
			grant_type: 'refresh_token',
			refresh_token: refresh_token,
		}

	}).then(
		function (result) {
			access_token = result.access_token;
		},
	);
}

// 1日に一度巡回し、更新された各国のヒットソングの情報
let ranking = [
	["AE", "by Adele", "Easy On Me", "46IZ0fSY2mpAiktS3KOqds", "https://spotifycharts.com/regional/ae/daily/latest", "https://i.scdn.co/image/ab67616d00004851c6b577e4c4a6d326354a89f7"],
	["AR", "by TINI, L-Gante", "Bar", "0lJE8f0lx8mUSfMyxeYpiC", "https://spotifycharts.com/regional/ar/daily/latest", "https://i.scdn.co/image/ab67616d000048517b1a8b1a92561bb5d16d6b4c"],
	// 以後略
];

// 特定の国のヒットソングを再生する
function play_sound(CountryCodes) {
	for (let i = 0; i < ranking.length; i++) {
		if (ranking[i][0] == CountryCodes) {
			var spotify_data = {
				uris: ["spotify:track:2MvIexkUblP1QdpBzKot3N"],
			};
			potify_data.uris[0] = 'spotify:track:' + ranking[i][3];

			// 曲を再生
			$.ajax({
				url: 'https://api.spotify.com/v1/me/player/play',
				type: 'PUT',
				headers: {
					'Authorization': 'Bearer ' + access_token,
				},
				data: JSON.stringify(spotify_data),
			}).then(
				function (result) {
				},
				function () {
				}
			);
			break;
		}
	}
}

##まとめ
本記事では、緯度・経度情報を入力とし、各種Web APIで様々な情報を取得する例を示しました。どれも簡単に有益な情報が取得できるAPIばかりですので、是非使って見てください。

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6