Google+ API with OAuth2.0
Google+のAPIを使うには、API keyを使う方法と、OAuth2.0で認証する方法があるらしい。
OAuthの使い方については、こちらのサイトなどを参考にしました。
- API Reference | Google+ Platform for Web | Google Developers
- OAuth 2.0 for Mobile & Desktop Apps | Google Identity Platform | Google Developers
- OAuth2.0によるGoogle+ APIのアクセス方法
- Google Code Archive - Long-term storage for Google Code Project Hosting.
かなり細かく説明されているので、上のサイトを見ながらやっていけば分かるのであまり書くこともないのだけど、Net::Twitter風にアクセストークンを取得するコードを書くとこんな感じ。Client ID/SecretはGoogle APIs Consoleのページから作成します。
use strict; use warnings; use utf8; use Encode; use JSON::XS; use LWP::UserAgent; use HTTP::Request::Common qw/POST/; my $auth_uri_base = 'https://accounts.google.com/o/oauth2/auth'; my $token_uri_base = 'https://accounts.google.com/o/oauth2/token'; my $redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'; my $scope = 'https://www.googleapis.com/auth/plus.me'; my $client_id = '[Your Client ID]'; my $client_secret = '[Your Client Secret]' my $auth_uri = sprintf("%s?response_type=code&client_id=%s&redirect_uri=%s&scope=%s", $auth_uri_base, $client_id, $redirect_uri, $scope); print "Authorize this app and enter the PIN# from:\n", $auth_uri, "\n\nPIN = "; my $pin = <STDIN>; # wait for input $pin =~ tr/\x0A\x0D//d; my $req = POST($token_uri_base, [ client_id => $client_id, client_secret => $client_secret, redirect_uri => $redirect_uri, grant_type => 'authorization_code', code => $pin, ]); my $ua = LWP::UserAgent->new; my $res = $ua->request($req); if ($res->is_success) { my $coder = JSON::XS->new->utf8(1); my $hash = $coder->decode($res->content); print "\n"; foreach(keys %$hash){ print "$_\t : $hash->{$_}\n"; } } else { print $res->status_line, "\n"; }
パラメーターのエスケープ処理をさぼってるけど、動いてるのでまあいいでしょう。
$ perl get_token_google.pl Authorize this app and enter the PIN# from: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=[Your Client ID]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/plus.me PIN = [PIN code] refresh_token : [Refresh Token] expires_in : 3600 id_token : [ID Token] access_token : [Access Token] token_type : Bearer
id_tokenとはなんぞや?と思って調べると、JWT(JSON Web Token)らしい。で、JWTってなんぞや?と思って調べると、webアプリケーションなどのserver-to-serverで使う、と書いてあるが、よく分からん。
Using OAuth 2.0 for Server to Server Applications | Google Identity Platform | Google Developers
とりあえずid_tokenは置いておいて、Perlからaccess_tokenを使うとこんな感じ。
use warnings; use utf8; use Encode; use JSON::XS; use LWP::UserAgent; use HTTP::Request::Common qw/GET/; use YAML::Syck; $YAML::Syck::Headless = 1; $YAML::Syck::SortKeys = 1; $YAML::Syck::ImplicitUnicode = 1; binmode STDOUT, ":encoding(utf8)"; my $id = shift; my $uri = "https://www.googleapis.com/plus/v1/people/$id"; my $access_token = '[Your Access Token]'; my $ua = LWP::UserAgent->new; my $req = GET($uri, (Authorization => "Bearer $access_token")); print "Request :\n" . $req->as_string; my $res = $ua->request($req); print "Response :\n"; print Dump(JSON::XS->new->utf8(1)->decode($res->content))
$ perl people_get.pl 102808008463301583196 Request : GET https://www.googleapis.com/plus/v1/people/102808008463301583196 Authorization: Bearer [Your Access Token] Response : aboutMe: 所属事務所/AKS ニックネーム/さくら<br /> displayName: 宮脇咲良 etag: "\"seVFOlIgH91k2i-GrbizYfaw_AM/kyq92wdTx-ArgG8c6itrCUj24bw\"" gender: female id: '102808008463301583196' image: url: https://lh6.googleusercontent.com/-P-JDWJDjao8/AAAAAAAAAAI/AAAAAAADiJM/Bdh_SvtPMtY/photo.jpg?sz=50 isPlusUser: !!perl/scalar:JSON::XS::Boolean 1 kind: plus#person name: familyName: 宮脇 givenName: 咲良 objectType: person tagline: HKT48 url: https://plus.google.com/102808008463301583196 urls: - label: HKT48公式サイト value: http://www.hkt48.jp/profile/sakura_miyawaki.html - label: Amebaブログ value: http://ameblo.jp/hkt48/ verified: !!perl/scalar:JSON::XS::Boolean 0
ほう。
面倒くさそうだなーと思っていたけど、単にユーザーとして使う分には意外と簡単だった。
あと、refresh_token の使い方がいまいち分からんかったのだけど、access_tokenは3600秒で期限切れになってしまうようなので、再びaccess_tokenを取り直す時に使うらしい。
$ curl -D - -H "Authorization: Bearer [Expired Access Token]" https://www.googleapis.com/plus/v1/people/102808008463301583196 HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="https://www.google.com/accounts/AuthSubRequest", error=invalid_token Content-Type: application/json; charset=UTF-8 Date: Mon, 23 Sep 2013 00:14:54 GMT Expires: Mon, 23 Sep 2013 00:14:54 GMT Cache-Control: private, max-age=0 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Server: GSE Alternate-Protocol: 443:quic Transfer-Encoding: chunked { "error": { "errors": [ { "domain": "global", "reason": "authError", "message": "Invalid Credentials", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Invalid Credentials" } }
$ curl -d refresh_token=[Refresh Token] -d client_id=[Client ID] -d client_secret=[Client Secret] -d grant_type=refresh_token https://accounts.google.com/o/oauth2/token { "access_token" : "[New Access Token]", "token_type" : "Bearer", "expires_in" : 3600, "id_token" : "[ID Token]" }
$ curl -H "Authorization: Bearer [New Access Token]" https://www.googleapis.com/plus/v1/people/102808008463301583196 { "kind": "plus#person", "etag": "\"seVFOlIgH91k2i-GrbizYfaw_AM/kyq92wdTx-ArgG8c6itrCUj24bw\"", "gender": "female", "urls": [ { "value": "http://www.hkt48.jp/profile/sakura_miyawaki.html", "label": "HKT48公式サイト" }, { "value": "http://ameblo.jp/hkt48/", "label": "Amebaブログ" } ], "objectType": "person", "id": "102808008463301583196", "displayName": "宮脇咲良", "name": { "familyName": "宮脇", "givenName": "咲良" }, "tagline": "HKT48", "aboutMe": "所属事務所/AKS ニックネーム/さくら\u003cbr /\u003e", "url": "https://plus.google.com/102808008463301583196", "image": { "url": "https://lh6.googleusercontent.com/-P-JDWJDjao8/AAAAAAAAAAI/AAAAAAADiJM/Bdh_SvtPMtY/photo.jpg?sz=50" }, "isPlusUser": true, "verified": false }
やったね。
レスポンスコードが401ならtokenをrefreshする、という感じでOKみたい。
追記、というかこちらが本題なのですが
そもそもの動機としては、Google+からHKT48メンバーの発言を監視してtwitterにpostするスクリプトを作ったことでして。
簡単なのでAPI keyを使った実装でしばらく運用していたのですが、現時点では10分ごとに実行するとAPI keyの許容量の5〜6割、5分おきに実行すると限界を超えて使えなくなってしまう。最初気付かずに「全然更新されないなー」などと思ってた。
HKTメンバーが39人なので*1、5分毎に投稿を取得すると一日で39*24*60/5 = 11232、10kちょいになりますね。
Google+ API (Sign-in) - For methods that are allowed by the scope https://www.googleapis.com/auth/plus.login (people.get, people.list, moments.insert, moments.remove and moments.list)
Google+ API - For all other methods
https://developers.google.com/+/api/#quota
Sign-inの方が20,000,000 requests/day、その他が10,000 requests/day。なるほど、サインインすれば20M/day使えるのかーやったーと思っていたのだけど、上に書いてあるAPIがSign-inとして数えられるらしく、サインインしたところでその他のAPI(たとえばactivities.listとか)はその他として計上されるらしい。じゃあわざわざOAuth使う意味ないね、面倒なだけだし・・・。
もう複数アカウント、あるいは複数プロジェクトを作って回すしかないか・・・と思いつつ、ダメ元でquotaを増やすリクエストをしてみたところ、3日くらいでメールをいただきまして増やしてもらえた!やった!
とりあえず10倍に増やしてもらったので、当分は持ちそう。
画像はquotaが増えた後のものなので上限が10%になってるけど、当時はここで100%になってました。冷静に考えれば、5分レベルのリアルタイムさは必要としてなかったのだった。
ところで、twilogで統計情報取ると、彼女たちの生活リズムが丸分かりですごくいけないことをしている気分になりますな。