Google+のシェア数を取得する 〜Ajax編〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
海外の洗剤……かな?

この記事を三行にまとめると

Ajaxによる非同期通信でシェア数を取ってみたいと思います
jQueryとXMLHttpRequestは単体での取得ができませんでした
AngularJSはjavascriptだけで完結してます
先日、Google+の仕様変更によりシェア数の取得ができなくなった的な話をしました。

Google+のシェア数を取得するためにSNS Count Cacheを魔改造してみた

この時はPHPでシェア数を取る方法とそれをWordpressのプラグインに応用するやり方をやりましたが、今度はjavascriptで取得してみようということで、Ajaxによる非同期通信でシェア数を取ってみたいと思います。

今回は以下の三つのパターンで取得してみました。

・AngularJS
・jQuery
・XMLHttpRequest

ただ、jQueryとXMLHttpRequestは単体での取得ができませんでした。クロスドメインの問題をどうにも解決できなくて……だから前回やったPHPとの組み合わせで取得する感じになってます。AngularJSはjavascriptだけで完結してます。

そんな難しいことはやってないので「AngularJSなんか使ってんじゃねえ。俺はjQueryしか知らねえんだバーロー」って人でも大丈夫……のはず。



AngularJSで取得する

基本的なやり方は前回のPHPと一緒です。

まず、カウントを表示する部分のHTMLをざっくりと。

<body ng-app="myApp">
  <div ng-controller="GoogleCountCtrl">
    シェア数:<span id="google_count"></span>
  </div>
</body>

「google_count」のidを持つspanタグの中に取得したシェア数を表示するという想定です。

ではjavascriptの部分をば。

<script>
app = angular.module('myApp', []);
app.controller('GoogleCountCtrl', function($scope, $http) {}).run(['$window', '$http', function($window, $http) {
  $http({
    url: "https://clients6.google.com/rpc",
    method: "POST",
    headers: {'Content-Type':'application/json'},
    data: {
      'method':'pos.plusones.get',
      'params':{
        'id':'https://norm-nois.com/blog/archives/3962'
      },
      'apiVersion':'v1'
    }
  }).then(function(res){
    var count = res.data.result.metadata.globalCounts.count;
    document.getElementById('google_count').innerHTML = count;
  });
}]);
</script>

取得先のURLも送信するパラメータもこないだのPHPの時と同じです。idのところに取得したいページのURLを入れる。「headers」のパラメータは書かなくてもたぶん正常に動作しますが、一応jsonデータをPOSTしてんだぞってことを強調するためにあえて書いときました。

今回はページの読み込み後に自動的に取得の処理が走るようにしています。onload的な感じですね。runというメソッドを使えば実現できます。

正常にリクエストが処理されれば「data.result.metadata.globalCounts.count」ってところにシェア数が入っているので、それを使って任意の場所に数字を表示させればオーケーです。



クロスドメイン問題

理論上は同じやり方でできるはずなので、こんな感じのコードを書けばjQueryでも取得できそうだな〜なんて楽観的に考えてたのですが、どうにも上手くいきませんでした。

$.ajax({
  type:'POST',
  url:'https://clients6.google.com/rpc',
  data:{
    'method':'pos.plusones.get',
    'params':{
      'id':'https://norm-nois.com/blog/archives/3962'
    },
    'apiVersion':'v1'
  },
  contentType:'application/json',
  dataType:'json',
  crossDomain:true
}).done(function(res){
  console.log(res);
})

jQueryの$.ajaxには「crossDomain」という設定項目があるので、これをtrueにすればいけんのかなとか思ったんですが、話はそう単純ではなかったみたいです。

実際やってみると以下のようなエラーが返ってくる。

XMLHttpRequest cannot load https://clients6.google.com/rpc. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://norm-nois.com/blog/archives/3962' is therefore not allowed access.

今はクロスドメインに関するガードも固くなっておりまして……つまり自分のとこじゃないドメインへAjaxでリクエストを投げようとしても受けつけてもらえないことが多くなりました。

これを解決する方法としては、一つはリクエストを受け取るサーバーの「Access-Control-Allow-Origin」というヘッダでこちらのドメインを許可してもらうやり方があります。上記のエラーでもAccess-Control-Allow-Originヘッダがどうたらこうたらと言ってますね。

例えばあかつきのお宿からのリクエストを許可してもらうには、こんな記述が必要になる。

header('Access-Control-Allow-Origin: https://norm-nois.com');

これはPHPでヘッダを追加した場合。どこからでもリクエストを受けつけたければワイルドカードを使えば良い。

header('Access-Control-Allow-Origin: *');

しかしこれは相手側の設定の話なので、今回だとgoogleさんの方でこの設定がされていなければどーにもならない。

あとは「jsonp」っていうのを使うとクロスドメインでもリクエストを投げることが可能になるのですが、これはGETリクエストしか使えないらしいので、POSTができない。今回の取得先はクエリ形式だと受けつけてもらえないので、GETでURLにパラメータをくっつけてリクエストしてもエラーになっちゃう。



jQueryで取得する

そんなわけでjQueryで相手先に直接コンタクトを取るのは難しいようなので、間にPHPを一枚噛ませて取得する方法を試してみたいと思います。

まず、シェア数取得用のPHPファイルを作成。ここでは「google_plus.php」としましょう。

//google_plus.php
$base_url = 'https://clients6.google.com/rpc';
$params = array(
  'method' => 'pos.plusones.get',
  'params' => array(
    'id' => 'https://norm-nois.com/blog/archives/3962',
  ),
  'apiVersion' => 'v1',
);
 
$ch = curl_init();  
curl_setopt($ch, CURLOPT_URL, $base_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,  json_encode($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
 
$result = curl_exec($ch);
curl_close($ch);

$json = json_decode($result, true);
echo $json['result']['metadata']['globalCounts']['count'];

この前と同じですね。取得できたらシェア数をechoで出力させてます。このファイルを「https://norm-nois.com/google_plus.php」とかでアクセスできる状態にしておく。

HTMLとjsはこんな感じ。

シェア数:<span id="google_count"></span>

<script>
$(function(){
  $.ajax({
    type:'GET',
    url:'https://norm-nois.com/google_plus.php',
  }).done(function(count){
    $('#google_count').text(count);
  });
});
</script>

これならAjaxのリクエスト先は自分のところなのでクロスドメインがどーのこーのって部分は回避できる。



XMLHttpRequestで取得する

やり方はjQueryと一緒です。なのでPHP部分は省略します。さっきと同じようにgoogle_plus.phpにアクセスするところだけ。

シェア数:<span id="google_count"></span>

<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://norm-nois.com/google_plus.php');
xhr.onload = function(e) {
  document.getElementById('google_count').innerHTML = xhr.responseText;
}
xhr.send();
</script>

正常に取得できれば「responseText」ってところにシェア数が入っているので、それを使えば表示できます。






Ajaxで〜と言いつつ、実質ほとんどPHP頼りな感じになってしまいましたが、とりあえずこんなやり方も考えられますぞってことで。

しかしクロスドメインがダメなら何で逆にAngularJSは問題なく取得できたんだろな……謎です。もしかしたらそのうちAngularJSも同じエラーが出るようになってしまうかもしれません。

ともあれ、ページ読み込み時にリアルタイムで取得したいような場合などがあれば、上記の方法を試してみるのも一つの手かと。
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください