Google Analytics APIを使用しページごとのセッション数を取得
この記事に書かれていること
- Google Analyticsでできることの軽い説明
- Google Analytics APIを使用し、ページごとのセッション数を取得したコードについてまとめ
背景
コーポレートサイトのブログ記事の人気ランキングを実装のために、ブログの記事ごとのセッション数を取得する必要がありました。
そこで、Google Analytics APIを使用しデータを取得し、実装しました。
Google Analyticsでできること。
Google Analyticsは、シェアNo.1のアクセス解析ツールで、Googleアナリティクスを使えば、Webサイト運営に必要なデータはほぼ見ることができます。
- リアルタイムの利用状況
- ユーザーの基本属性
- ユーザーがどこから来たか
- サイト内でのユーザーの動き
- Webサイトの成果
などです。
実装
準備
まず必要な登録や、設定、情報を取得する必要がありますが、 以下の記事をご参照ください。
また今回の実装においては、大変参考になった記事です🙇♂️
https://qiita.com/Sa2Knight/items/0b61efc2be0bdf33ec48
https://qiita.com/ryota-sasabe/items/a5efd2aac244cfcce5c7
全体像
lib/tasks/google_analytics.rake
に具体的な処理、
lib/google_analytics_reporting.rb
にGoogleAnalyticsReportingクラスを定義、
必要な情報、秘匿情報は各種ファイルに記述しました。
config/environments/
config/credentials
# lib/tasks/google_analytics.rake namespace :google_analytics do desc 'update_articles_sessions_count_with_Google_Analytics' task update_articles_sessions_count: :environment do reporting = GoogleAnalyticsReporting.new( '2019-01-01', 'today', 'ga:uniquePageviews', 'ga:pagePath', ) reporting = reporting.get_reporting articles_pages = reporting.rows.select { |row| row.dimensions.first.match(%r{articles/.+}) } articles = [] Article.published.find_each do |article| article = article.attributes article['category'] = Article.categories[article['category']] article['public_status'] = Article.public_statuses[article['public_status']] articles_page = articles_pages.find { |articles_page| articles_page.dimensions.first.gsub("/articles/", "") == article['uid'] } next if articles_page.nil? article['sessions_count'] = articles_page.metrics.first.values.first.to_i articles << article end if articles.present? Article.upsert_all(articles) Article.reindex end end end
# lib/google_analytics_reporting.rb class GoogleAnalyticsReporting require 'google/apis/analyticsreporting_v4' SCOPE = ['https://www.googleapis.com/auth/analytics.readonly'].freeze def initialize(start_date, end_date, metric_type, dimension_type) @analytics = Google::Apis::AnalyticsreportingV4 @client = @analytics::AnalyticsReportingService.new ENV['GOOGLE_PRIVATE_KEY'] = Rails.application.credentials.google_analytics[:private_key] ENV['GOOGLE_CLIENT_EMAIL'] = Rails.application.credentials.google_analytics[:client_email] ENV['GOOGLE_PROJECT_ID'] = Rails.application.credentials.google_analytics[:project_id] @start_date = start_date @end_date = end_date @metric_type = metric_type @dimension_type = dimension_type @client.authorization = Google::Auth::ServiceAccountCredentials.make_creds( scope: SCOPE ) end def get_reporting request = build_request response = @client.batch_get_reports(request) response.reports.first.data end def build_request date_range = @analytics::DateRange.new(start_date: @start_date, end_date: @end_date) metric = @analytics::Metric.new(expression: @metric_type) dimension = @analytics::Dimension.new(name: @dimension_type) @analytics::GetReportsRequest.new( report_requests: [@analytics::ReportRequest.new( view_id: Rails.configuration.google_analytics_view_id, metrics: [metric], dimensions: [dimension], date_ranges: [date_range] )] ) end end
コード解説
# lib/google_analytics_reporting.rb class GoogleAnalyticsReporting require 'google/apis/analyticsreporting_v4' SCOPE = ['https://www.googleapis.com/auth/analytics.readonly'].freeze def initialize(start_date, end_date, metric_type, dimension_type) @analytics = Google::Apis::AnalyticsreportingV4 @client = @analytics::AnalyticsReportingService.new
まずクラスので必要な情報を定義していきます。
# lib/google_analytics_reporting.rb ENV['GOOGLE_PRIVATE_KEY'] = Rails.application.credentials.google_analytics[:private_key] ENV['GOOGLE_CLIENT_EMAIL'] = Rails.application.credentials.google_analytics[:client_email] ENV['GOOGLE_PROJECT_ID'] = Rails.application.credentials.google_analytics[:project_id]
は、認証のために必要な情報で、参考にしたqiitaにはjsonファイルで記述されていますが、環境変数に定義しても認証が行えるので 今回はこのように定義しました。 中身は、秘匿情報、環境ごとに取得したいのでcredentialsに記述しました。
# lib/google_analytics_reporting.rb @start_date = start_date @end_date = end_date @metric_type = metric_type @dimension_type = dimension_type
データの取得の期間、メトリックとディメンション(条件のようなもの)を引数で渡せるように定義しました。 将来、異なる情報を取得したいときにもこのクラスを使用できます。
# lib/google_analytics_reporting.rb @client.authorization = Google::Auth::ServiceAccountCredentials.make_creds( scope: SCOPE ) end
initializeが呼び出されたときに認証を行なっています。
# lib/tasks/google_analytics.rake reporting = GoogleAnalyticsReporting.new( '2019-01-01', 'today', 'ga:uniquePageviews', 'ga:pagePath', )
rake taskにてクラスをインスタンス化させます。 その際に、今回取得したいデータの条件を引数として渡してあげます。
# lib/tasks/google_analytics.rake reporting = reporting.get_reporting articles_pages = reporting.rows.select { |row| row.dimensions.first.match(%r{articles/.+}) }
get_reportingメソッドでGAからのデータを取得します。中身は、
# lib/google_analytics_reporting.rb def get_reporting request = build_request response = @client.batch_get_reports(request) response.reports.first.data end
# lib/google_analytics_reporting.rb def build_request date_range = @analytics::DateRange.new(start_date: @start_date, end_date: @end_date) metric = @analytics::Metric.new(expression: @metric_type) dimension = @analytics::Dimension.new(name: @dimension_type) @analytics::GetReportsRequest.new( report_requests: [@analytics::ReportRequest.new( view_id: Rails.configuration.google_analytics_view_id, metrics: [metric], dimensions: [dimension], date_ranges: [date_range] )] ) end
となっており、先ほど引数で渡した条件からデータを取得しています。
その際にview_idを渡していますが、これはconfig/environments/
以下の環境ごとのファイルにそれぞれ定義しています。
# lib/tasks/google_analytics.rake articles = [] Article.published.find_each do |article| article = article.attributes article['category'] = Article.categories[article['category']] article['public_status'] = Article.public_statuses[article['public_status']] articles_page = articles_pages.find { |articles_page| articles_page.dimensions.first.gsub("/articles/", "") == article['uid'] } next if articles_page.nil? article['sessions_count'] = articles_page.metrics.first.values.first.to_i articles << article end if articles.present? Article.upsert_all(articles) Article.reindex end
ここで、dbに存在する。ブログ記事のデータを取得し、GAと同じuid(url)のもののsessions_countを更新させる処理を行なっています。
レコード数は少ないとは思いますが、大量にデータを扱っても良いようにfind_each
を使用しました。
https://blog.toshimaru.net/rails-find_each/
また、1件ずつsqlを発行するのは、処理的によくないのでbulk_insertのupsert_all
を使いました。
最後に、reindexをしているのは、elastic searchを使用しているため、upsert_all
して値を更新したらreindexをしないといけないからです。
最後に
APIを使用するのは初めてだったので、最初はqiitaの丸写しに近いものでしたが、コードレビューを行なってもらい、より自分の実装したいものになっていきました。 また、内容の理解やrubyの理解も深まりました。 同じ処理でも、よりパフォーマンスの良い処理、実は省くことのできる記述などがありました。例えばjsonファイルではなく必要な情報だけ環境変数に記述すれば良いところなど。
最初にqiitaからヒントを得るのは悪くないと思いますが、そこから
- コピペしたものの中身はどうなっているのか
- 何が必要なもので、何が不必要なのか
- 削れる処理はないか
- よりパフォーマンスをあげるには
をもう少し自分で考え、実装できるようにしないとなと思いました。