rcmdnk's blog
Last update

20150210_popularlist_200_200

サイドバーのRecent Postsを画像付きにしたはてなブックマークの人気リストを画像付きにしてみる、 に引き続き Google AnalyticsのView数を取ってきてView数を表示したりランキングを作ったり してみました。

AnalyticsのView数をRubyを使って取ってくる

スクリプトの準備

最終的にOctopressのプラグインにして記事生成時にリストを作りますが、 取り敢えずテストとして簡単なスクリプトで取って来れる事を確認します。

google/google-api-ruby-client を使うことで簡単にGoogle関連のサービスにアクセス出来るようになります。

analyticsTest.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env ruby

require 'google/api_client'
require 'chronic'

# Update these to match your own apps credentials
service_account_email = '[email protected]' # Email of service account
key_file = 'YOURFILE.P12' # File containing your private key
key_secret = 'notasecret' # Password to unlock private key
profileID = 'PROFILE_ID' # Analytics profile ID.

client = Google::APIClient.new(:application_name => 'Octopress', :application_version => '0.0.1')

# Load our credentials for the service account
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
client.authorization = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => 'https://www.googleapis.com/auth/analytics.readonly',
  :issuer => service_account_email,
  :signing_key => key)

# Request a token for our service account
client.authorization.fetch_access_token!

analytics = client.discovered_api('analytics','v3')

startDate = Chronic.parse('3 years ago').strftime("%Y-%m-%d")
endDate = Chronic.parse('now').strftime("%Y-%m-%d")

ret = client.execute(:api_method => analytics.data.ga.get, :parameters => {
  'ids' => "ga:" + profileID,
  'start-date' => startDate,
  'end-date' => endDate,
  'dimensions' => "ga:pagePath",
  'metrics' => "ga:pageviews",
  'max-results' => 10,
})

#p ret.data

ret.data.rows.each do |r|
  print r.join("\t"), "\n"
end

こんなスクリプト。

追記: 2016/01/18

Google API Clientが0.8.6から0.9にアップデートされて仕様ちょっと変わって 書き換える事が必要になりました。

追記ここまで

Gemfile

gem 'chronic'
gem 'google-api-client'

を足してbundle installするか

gem install google-api-client chronic

Chronic の方は必須では無いですが、上の例にあるように 時間指定するのに~ years agonowと言った指定方法が使えるので便利です。

Google Developers Consoleへ登録

このスクリプトを有効にするために、まず、 Google Developers Console へ新規プロジェクトを登録します。

上記のページからプロジェクトを作成ボタンを押してAnalyticsなりなんなりの 適当な名前のプロジェクトを作成します。

プロジェクトを選択すると、左の一覧に APIと認証APIという欄があるのでそれをクリック。

上の方に現在有効なAPI一覧が表示されてますが、その下にある APIを見るの下のフィルタリング欄でAnalyticsと入れて Analytics APIを探してこれを右のステータスボタンを使ってONにします。

console

Analytics APIONになったら APIと認証認証情報へ行き、 新しいクライアントIDを作成をクリックして新しいIDを生成します。

出てくるポップアップでサービスアカウントを選んでクライアントIDを作成を押すと、 秘密キーのダウンロード開始(もしくはブラウザでどうやって開くか聞かれる)とともに、 秘密キーのパスワードが表示されます。 (通常はこのパスワードはnotasecretで共通な様です。)

作成が成功すると、 認証情報のページにサービスアカウントとして新しいクライアントIDが登録されているはずです。

ここにあるメールアドレスが後で必要になるのでメモっておきます。

取り敢えずここまででGoogle Developers Consoleでの作業は終了。

Google Analyticsでの設定

Google Analyticsで先ほど作ったクライアントIDで アクセス出来るように設定します。

アクセスしたいアカウントを選んで、上にあるアナリティクス設定へ行きます。

ここで、プロパティ欄にあるユーザー管理へ行き、 先ほどGoogle Developers Consoleで得たメールアドレスを 権限を付与するユーザーに入力して右のタブら表示と分析を選んで 追加します。

analytics

これでアクセス出来る様になりますが、 すぐには反映されずに 数分程時間がかかるようなのですぐに繋がらなかった場合には 少し待ちます。

ついでに、上のスクリプトに必要な情報として、 設定ページの右側のビュー欄のビュー設定を選び、 一番上のビューIDという8桁の数字をメモっておきます。

スクリプトの編集

ひと通り準備が終わったのでスクリプトに必要な情報を加えていきます。

上のスクリプトの中で

  • [email protected]’: Google Developers Consoleで得たメールアドレスに変更。
    • これを自分の通常のGoogleのメールアドレスだと思って少し時間を無駄にしました。。。
  • ‘YOURFILE.P12’: 先ほどクライアントID作成時にダウンロードした秘密キーへのパスに変更。
  • ‘notasecret’: もし、クライアントID作成時に違うパスワードが出たらこれも変更。
  • ‘PROFILE_ID’: 先ほどAnalyticsのビュー設定から取得したビューIDに変更。

編集できたら

$ ruby analyticsTest.rb
/blog/2013/05/blog-octopress 10
/blog/2013/07/blog-octopress 33
...

みたいにページとView数が取得出来たらOKです。

$ ruby analyticsTest.rb
/Library/Ruby/Gems/2.0.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:947:in `fetch_access_token': Authorization failed.  Server message: (Signet::AuthorizationError)
{
  "error" : "invalid_grant"
}
        from /Library/Ruby/Gems/2.0.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:964:in `fetch_access_token!'
        from test.rb:25:in `<main>'

みたいなのが出たらメールアドレスが間違ってる可能性が大きいです。

$ ruby test.rb
/Library/Ruby/Gems/2.0.0/gems/google-api-client-0.8.2/lib/google/api_client/auth/key_utils.rb:88:in `rescue in load_key': Invalid keyfile or passphrase (ArgumentError)
        from /Library/Ruby/Gems/2.0.0/gems/google-api-client-0.8.2/lib/google/api_client/auth/key_utils.rb:80:in `load_key'
        from /Library/Ruby/Gems/2.0.0/gems/google-api-client-0.8.2/lib/google/api_client/auth/key_utils.rb:34:in `load_from_pkcs12'
        from test.rb:15:in `<main>'

であれば秘密鍵へのパスが間違ってるかパスワードが間違ってるか、です。

これらが出ずにページやView数の表示が出ない場合は

#p ret.data

のところのコメントを外して帰ってくるのが出たりしてチェックします。

#<Google::APIClient::Schema::Analytics::V3::GaData:0x3fe8954aec60 DATA:{"error"=>{"errors"=>[{"domain"=>"global", "reason"=>"insufficientPermissions", "message"=>"User does not have sufficient permissions for this profile."}], "code"=>403, "message"=>"User does not have sufficient permissions for this profile."}}>

などと出たら、 指定したクライアントIDがAnalyticsの方で登録が済んでいないか、 ビューIDが間違ってる可能性があります。

Octopressのプラグインの導入

Rubyを使ってAnalyticsへアクセス出来るようになったら Octopressでの準備を行います。

3rd party plugins

ここにoctopress-popular-posts があったのでこれを使いたいと思います。

コレを使うには octopress-page-view も必要です。

これらに入ってるplugins/page_view.rbplugins/popular_posts.rbpluginsへコピー。

このままだと上手く使えなくてそれぞれ以下の様な変更をしておきます。

page_view.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@@ -55,7 +55,7 @@
       tot = 0
       # display per post page view
       site.posts.each { |post|
-        url = (site.config['baseurl'] || '') + post.url + 'index.html'
+        url = (site.config['baseurl'] || '') + post.url
         hits = (results[url])? results[url].to_i : 0
         post.data.merge!("_pv" => hits)
         tot += hits
@@ -65,13 +65,9 @@ module Jekyll
       site.pages.each { |page|
         url = (site.config['baseurl'] || '') + page.url
         hits = (results[url])? results[url].to_i : 0
+        page.data.merge!("_pv" => hits)
         tot += hits
       }
-
-      # display total page view in page
-      site.pages.each { |page|
-        page.data.merge!("_pv" => tot)
-      }
     end
   end
popular_posts.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@@ -4,13 +4,14 @@

   class PopularPosts < Generator
     safe :true
-    priority :low
+    priority :lowest

     def generate(site)
       # require octopress-page-view plugin
       if !site.config['page-view']
         return
       end
+      n_posts = site.config['page-view']['n_posts']

       popular_posts = site.posts.sort do |px, py|
         if px.data['_pv'] == nil || py.data['_pv'] == nil then 0
@@ -20,6 +21,12 @@
         end
       end

+      site.posts.each { |post|
+        post.data.merge!("popular_posts" => popular_posts[0,n_posts])
+      }
+      site.pages.each { |page|
+        page.data.merge!("popular_posts" => popular_posts[0,n_posts])
+      }
       site.config.merge!('popular_posts' => popular_posts)
     end
   end

追記: 2015/02/10

prioritylowからlowestへ変更。 priorityはプラグインがロードされる順番を指定しますが、 :highest:high:normal:low:lowestの 指定が出来、:highestの物から実行されていきます。

プラグインの中にはタグページやカテゴリーのページなどを作るものもあり、 これらよりも先に上のプラグインが動いてしまうと まだsite.pagesの中に登録されてないので情報が入りません。

従って、このプラグインを:lowestにして、他のページ作成などのプラグイン (category_generator.rb等)よりも後に実行される様にする必要があります。 大概のプラグインは:lowが指定されています。 デフォルトは:normalみたいです。

Plugins

Method: Jekyll::Plugin.priority — Documentation for jekyll/jekyll (master)

追記ここまで

page_view.rbの方は余計なindex.htmlを別途付けて数が取得出来ないのでこれを消去。

追記: 2015/02/16

pageの方のPVの指定がおかしかったのでそれも直す様に変更。

追記ここまで

popular_posts.rbsite.config['page-view']['n_posts'] の設定は後で保存しておく数を_config.ymlから簡単に変更できる様にするための設定です。

下の方でsite.configpopular_postsを登録する代わりに、 各ページ、ポストにこの値を入れています。 今の環境だとこのsite.configへの変更が他の所に反映されず、 post等に入れると取得することが出来たのでこの様にしました。 これだと各ポスト毎に全く同じ変数を入れてく事になるので結構無駄ですが、 他に上手いやり方が思いつかなかったので取り敢えずの処置。

追記: 2015/06/09

何か勘違いしてたのかsite.config.popular_postsとか間違って呼んでたのか分かりませんが、 改めて試してみると

1
2
3
4
5
6
7
8
9
10
<section>
  <h1>Popular Posts</h1>
  <ul class="posts">
    {% for post in site.popular_posts limit:5 %}
    <li class="post index_click_box">
      {% include post_list.html %}
    </li>
    {% endfor %}
  </ul>
</section>

みたいにしておけば普通に取ってこれました。

ので、上の

site.posts.each { |post|
  post.data.merge!("popular_posts" => popular_posts[0,n_posts])
}
site.pages.each { |page|
  page.data.merge!("popular_posts" => popular_posts[0,n_posts])
}

の部分は削除しました。

追記ここまで

次に、各ページごとのView数の表示ですが、これはpage_view.rbの中で定義されている pageviewを使うと取得することが出来、 好きな所で

{% pageview %}

と呼べばそのページのView数が表示されます。

octopress-page-view の中にも source/_includes/custom/asides/pageview.htmlという サイドバーにビュー数を表示するだけのパーツが入っています。

一方、 octopress-popular-posts の中には source/_includes/custom/asides/popular_posts.html というファイルがあってこれがView数の多い順にリストをサイドバーに載せるものなので、 これを元に サイドバーのRecent Postsを画像付きにした でやったようなリストを作ります。

サイドバーのRecent Postsを画像付きにした の所で、imgタグが上手く動かないのを治すために別途source/_includes/asides/recent_post.html というファイルを作りましたが、 このView数によるランキングでも同じものが使えるので、共通にするためこれを source/_includes/post_list.htmlというファイルに置き換えます。

さらに下みたいな感じでView数の表示も出来るように変更。

source/_includes/post_list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<li class="post index_click_box">
  <div class="group">
    {% if post.ogimage and post.no_ogimage != true %}
    <div class="title-smallthumb">
      <a href="{{ root_url }}{{ post.url }}">{% img val:post.ogimage %}</a>
    </div>
    {% else %}
    <div class="title-smallthumb">
      <a href="{{ root_url }}{{ post.url }}">{% img val:site.sitelogo %}</a>
    </div>
    {% endif %}
    <a class="click_box_link" href="{{ root_url }}{{ post.url }}">{% if site.titlecase %}{{ post.title | titlecase }}{% else %}{{ post.title }}{% endif %}</a>{% if site.page-view.show_views and post._pv %}<br><span class="views">{{post._pv}} views</span>{% endif %}
  </div>
</li>

View数の化粧としてsass/plugins/_plugins.scss

sass/plugins/_plugins.scss
1
2
3
4
5
6
7
8
9
.views {
  background-color: #ccccff;
  font-weight: bold;
  font-size: 0.9em;
  font-style: normal;
  display: inline;
  color: blue;
  text-decoration: underline;
}

とでも書いておきます。

最後に、_config.yml

_config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
# page-view settings
page-view:
  service_account_email: [email protected] # service accoutn email
  key_file: YOURFILE.P12    # service account private key file
  key_secret: notasecret    # service account private key's password
  profileID: ga:PROFILE_ID  #ga:XXXXXXXX
  start: 3 years ago        # Beginning of report
  end: now                  # End of report
  metric: ga:pageviews      # Metric code
  segment: gaid::-1         # all visits
  filters:                  # optional
  n_posts: 5                # Number of popular posts
  show_views: true          # If n_views is shown or not

みたいな設定をすれば(メールやPROFILE_ID等を適時変更)、

popularlist

こんな感じのサイドバーが出来ます。

後は適当に、全ての期間の合計にしたければ start10 years ago等十分大きい値にしたり、 1 month agoで過去一ヶ月分だけ撮ったり n_postsで表示する数を変更したり、 View数は要らないのであればshow_viesfalseにしたりしてください。

Sponsored Links
Sponsored Links

« はてなブックマークの人気リストを画像付きにしてみる サイドバーにランダム記事リストを作る »

}