ブラウザでタイルを取得する
stravaからglobal heat mapのデータを頂く で言及しましたが
StravaのHeatmapタイルでZoom 12以上を指定すると
認証(authentication)が必要である旨が表示されます。
$ curl https://heatmap-external-b.strava.com/tiles/ride/hot/12/3636/1610.png
authentication is now required for data access beyond zoom level 12, please login to strava.com and then visit /auth
Stravaにログインした後に
指示の通り /auth を訪れると cookie をセットした旨のメッセージが表示され
タイル取得の準備が完了となります。
https://heatmap-external-b.strava.com/auth にブラウザでアクセス
Logged in as AthleteId(XXXXXXX), cloudfront cookies set
※IDは伏せました
未ログイン時は
not logged in
多くのcookieを保存しているようですが、
タイル取得に必要なものは以下の3つのようです。
- CloudFront-Key-PairId
- CloudFront-Policy
- CloudFront-Signature
2019-09-19 14:47(JST) の取得で、expireは
2019-09-26 05:47(UTC) = 14:47(JST) に設定されているので賞味期限は7日間
(結構長いじゃん!)
この状態でタイルを取得します。
URLが異なっている (tiles-auth) なので気を付けてください。
URLの例
https://heatmap-external-b.strava.com/tiles-auth/ride/hot/12/3636/1610.png
https://heatmap-external-b.strava.com/tiles-auth/ride/hot/13/7272/3220.png
https://heatmap-external-c.strava.com/tiles-auth/ride/hot/13/7272/3220.png?px=256
自動化の方針
課題は Strava にログインし、必要なcookieを取得する事
方針は色々ありますが...
- curlで突破
- mechanizeなどのスクレイピングで突破 --> cookie保存 --> そのcookieをcurlに食わす
- mechanizeなどのスクレイピングで突破 --> そのまま png (= tile) も取得
今回は 3 でやってみます
自動ログイン&タイル取得コード (Perl)
Perl + Mechanize で組んでみました
試行錯誤のあとの残るコードですが、主要部分を以下に示します
ポイントとなると思われる部分をコメントで記述してあります。
それぞれのポイントの解説はコードの後に。
(略)
use IO::Socket::SSL qw( SSL_VERIFY_NONE );
use IO::Socket::SSL qw( debug4 ); # ★ポイント(1)★ SSLのハンドシェイクのデバッグに有効
...
my $URL_STRAVA_LOGIN = "https://www.strava.com/login";
my $URL_STRAVA_TILE_AUTH = "https://heatmap-external-b.strava.com/auth";
my $URL_STRAVA_TILE_PNG = "https://heatmap-external-b.strava.com/tiles-auth/ride/hot/15/29088/12880.png";
...
### Mechanize Object Creation
my $mech = WWW::Mechanize->new(
cookie_jar => {},
autocheck => 1,
ssl_opts => {
#verify_hostname => 0, # 0 = disable SSL host check
#SSL_verify_mode => SSL_VERIFY_NONE,
#SSL_version => 'TLSv1_2', # SSL version TLSv1/TLSv1_1/TLSv1_2
#SSL_hostname => 'www.strava.com',
SSL_hostname => 'heatmap-external-b.strava.com', # ★ポイント(2)★ SSL_hostnameの設定!!
},
);
# $mech->proxy(['http', 'https'], undef);
$mech->agent_alias('Linux Mozilla');
...
### Strava login page
$mech->get($URL_STRAVA_LOGIN);
print_result($mech); # print_resultは自前の関数。なくてもよい
### input Strava's credential (user/pass) # ★ポイント(3)★ Facebook連動ログインはあきらめた
$mech->submit_form(
form_number => 1,
fields => {
email => $user,
password => $pass,
}
);
...
### Strava auth for tile
$mech->get($URL_STRAVA_TILE_AUTH); # ★ポイント(4)★ タイルのauth urlに一度訪問する
print_result($mech);
### Strava tile
$mech->get($URL_STRAVA_TILE_PNG); # ★ポイント(5)★ authタイル取得URLは "tiles-auth" なので注意!
open(OUT, "> tile.png");
print OUT $mech->content;
close(OUT);
(略)
ポイント(1) SSLのハンドシェイクのデバッグに有効
コードが動作した後は不要ですが、デバッグ中は有効にしておくと
SSLのハンドシェイクのどこで失敗したかがわかるので非常に有効でした。
use IO::Socket::SSL qw( debug4 ); # ★ポイント(1)★ SSLのハンドシェイクのデバッグに有効
ポイント(2) SSL_hostnameの設定 【重要】
一番のポイントでした
これがないと 14094410 エラーが発生してアクセスできません。
解決の手がかりはこちらでした。
OpenSSL APIメモ(handshake failure)
SNIへの対応が必要です。
具体的にはサーバ側にhostnameをわたす必要があります。
Mechanize(というか IO::Socket::SLL)での指定は以下になります。
my $mech = WWW::Mechanize->new(
cookie_jar => {},
autocheck => 1,
ssl_opts => {
#verify_hostname => 0, # 0 = disable SSL host check
#SSL_verify_mode => SSL_VERIFY_NONE,
#SSL_version => 'TLSv1_2', # SSL version TLSv1/TLSv1_1/TLSv1_2
#SSL_hostname => 'www.strava.com',
SSL_hostname => 'heatmap-external-b.strava.com', # ★ポイント(2)★ SSL_hostnameの設定!!
},
);
その他オプションについてはこちらを参照のこと
https://metacpan.org/pod/IO::Socket::SSL
ポイント(3) Facebook連動ログインはあきらめ、Strava user/pass でログイン
Facebookのページに飛んだあとどうしてもスマホにPINコードが飛んでこず
Facebookアカウントでのログインはあきらめました。
Stravaにパスワード設定して、email + passでログイン
$mech->submit_form(
form_number => 1,
fields => {
email => $user,
password => $pass,
}
);
ポイント(4) タイルのauth urlに一度訪問する
Strava様の指示通りに...
my $URL_STRAVA_TILE_AUTH = "https://heatmap-external-b.strava.com/auth";
$mech->get($URL_STRAVA_TILE_AUTH); # ★ポイント(4)★ タイルのauth urlに一度訪問する
ポイント(5) authタイル取得URLは "tiles-auth" なので注意
Zoom = 11までのタイルとはURLが異なるので注意してください
my $URL_STRAVA_TILE_PNG = "https://heatmap-external-b.strava.com/tiles-auth/ride/hot/15/29088/12880.png";
$mech->get($URL_STRAVA_TILE_PNG); # ★ポイント(5)★ authタイル取得URLは "tiles-auth" なので注意!
以上です