はじめに

InstaMapperは,iPhoneアプリ「GPS Tracker」で記録した位置情報へアクセスするための Web API(解説ページ,要ログイン)も提供しています.

APIキーを取得後(1つのAPIキーは1つのデバイスに対応するかと),特定のURLへ,このAPIキーやパラメータとともにリクエストを送信すると,対応する位置情報(のリスト)がCSV形式やJSON形式で返ってくるので,いろいろ加工して遊べそうです.

しかしながら,解説ページを読む限り,現状では,from_tsパラメータとnumパラメータとを組み合わせて「いついつから最大何個分の位置情報」といった感じにしか取得できないようです.

個人的には,作成した「track」に関連した位置情報群が取得できると幸せかも,と思っています.

ss-2009081501 on Flickr

せっかくこういった情報の表示や http://www.instamapper.com/trk?key=10390698753582733189 といったURLがあるのだから,track_keyパラメータで指定したり,from_tsパラメータとto_tsパラメータとの組み合わせで指定したり,とかできるべきだよね,ということですね.念のため,track_keyto_tsを実際に指定してみましたが,あっさり無視されてしまいました.

そんなわけで,両端の時刻を指定して,その間の位置情報群を取得できるようなperlモジュールっぽいものを書いてみました.勝手にNet::InstaMapperとか名前をつけてます.

以下,使い方とかサンプルとかソースコードとかです.

使い方

まず,set_api_keyメソッドで,取得したAPIキーを設定します.

use Net::InstaMapper;
Net::InstaMapper::set_api_key( '********************' );

get_positionsメソッドで指定した時刻間の位置情報群が得られます.

my $data = Net::InstaMapper::get_positions( '2009-08-14 18:18:14', '2009-08-14 19:08:33' );

また,get_positions_jsonメソッドで同様の情報をJSON形式(の文字列)で取得することもできます.

my $json = Net::InstaMapper::get_positions_json( '2009-08-14 18:18:14', '2009-08-14 19:08:33' );

できるのはこれだけです.

サンプル

時刻と標高(海抜?)のペアを取得するサンプルです.

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Data::Dumper;
use Net::InstaMapper;
 
sub d { print Dumper @_; }
 
Net::InstaMapper::set_api_key( '********************' );
Net::InstaMapper::hide_device_key( 1 );
 
my $data = Net::InstaMapper::get_positions( @ARGV );
$data = [ map { { t => $_->{timestamp}, h => $_->{altitude} } } @$data ];
d $data;

実行結果は次のようになります.

% ./instamapper-api.pl '2009-08-14 18:18:14' '2009-08-14 19:08:33'
$VAR1 = [
          {
            'h' => '74',
            't' => 1250241494
          },
          {
            'h' => '77',
            't' => 1250241554
          },
...
          {
            'h' => '78',
            't' => 1250244453
          },
          {
            'h' => '85',
            't' => 1250244513
          }
        ];
%

あとはこれをグラフにしたり,とかですかね.

おわりに

以上,InstaMapperのちょっと使いにくいAPIをちょこっとだけラップする,Net::InstaMapperとかいうモジュールっぽいものを書いてみた,というお話でした.

ソースコードを以下に載せておしまいとします.

ソースコード

package Net::InstaMapper;
use strict;
use warnings;
use utf8;
use Time::Local;
use LWP::UserAgent;
use JSON::Syck;
 
our $VERSION = 0.001001;
 
my $NUM_DATA_MAX    = 10000;
my $HIDE_DEVICE_KEY = 0;
my $API_KEY         = '';
 
 
# set_api_key( $api_key );
sub set_api_key {
  return ( $API_KEY = shift )  ?  1  :  0;
}
 
 
#
sub __get_time {
  my $datetime = shift || '';
  my $re = qr/(\d{4})\D(\d{2})\D(\d{2}) \D? (?:(\d{2})\D(\d{2})(?:\D(\d{2}))?)?/x;
  my @t = reverse $datetime =~ $re;
  if( @t ) { $t[5] -= 1900; $t[4] -= 1; }
  else     { @t = localtime time; }
  return timelocal @t;
}
 
 
# $arrayref = get_positions( $from, $to, $limit );
sub get_positions {
  my ( $from, $to, $limit ) = @_;
  my $from_ts = __get_time($from);
  my $to_ts   = __get_time($to);
 
  return []  unless $API_KEY;
 
  # refer http://www.instamapper.com/fe?page=api for details
  my $api_uri =
    sprintf 'https://www.instamapper.com/api?action=getPositions&key=%s&num=%d&from_ts=%s&format=json',
	    $API_KEY,
	    $limit  ||  $NUM_DATA_MAX,
	    $from_ts,
	    ;
 
  my $ua  = LWP::UserAgent->new;
  my $res = $ua->get( $api_uri );
 
  my $data = JSON::Syck::Load( $res->content  ||  {} )->{positions}  ||  [];
  $data = [
	   map {
	     $_->{device_key} = '*' x 13  if $HIDE_DEVICE_KEY;
	     $_;
	   }
	   grep {
	     $_->{timestamp} <= $to_ts;
	   }
	   @$data
	  ];
  return $data;
}
 
 
# $json = get_positions_json( $from, $to, $limit );
sub get_positions_json {
  my $data = get_positions( @_ );
  return JSON::Syck::Dump( $data );
}
 
 
# hide_device_key( $1_or_0 );
sub hide_device_key {
  return defined ( $HIDE_DEVICE_KEY = shift )  ?  1  :  0;
}
 
 
1;
__END__

こちらもあわせてどうぞ

コメントをどうぞ