Skip to content

Instantly share code, notes, and snippets.

@wschenk
Created December 4, 2014 22:48
Show Gist options
  • Save wschenk/d7f8650d619d8f68730a to your computer and use it in GitHub Desktop.
Save wschenk/d7f8650d619d8f68730a to your computer and use it in GitHub Desktop.
Scripting Google Analytics with ruby-api-client
#!/usr/bin/env ruby -KU
#
# This code has been adapted from
# https://github.com/google/google-api-ruby-client-samples/tree/master/drive
#
require 'thor'
require 'hirb'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'logger'
require 'csv'
API_VERSION = 'v3'
CACHED_API_FILE = "analytics-#{API_VERSION}.cache"
CREDENTIAL_STORE_FILE = "analytics-oauth2.json"
CLIENT_SECRETS_FILE = "client_secrets.json"
class AnalyticsClient
def initialize( file_caches = nil )
client
end
def client
return @client if @client
@client = Google::APIClient.new(:application_name => 'Analyics-CLI',
:application_version => '1.0.0')
# FileStorage stores auth credentials in a file, so they survive multiple runs
# of the application. This avoids prompting the user for authorization every
# time the access token expires, by remembering the refresh token.
# Note: FileStorage is not suitable for multi-user applications.
file_storage = Google::APIClient::FileStorage.new(CREDENTIAL_STORE_FILE)
if file_storage.authorization.nil?
client_secrets = Google::APIClient::ClientSecrets.load(CLIENT_SECRETS_FILE)
# The InstalledAppFlow is a helper class to handle the OAuth 2.0 installed
# application flow, which ties in with FileStorage to store credentials
# between runs.
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/analytics']
)
@client.authorization = flow.authorize(file_storage)
else
@client.authorization = file_storage.authorization
end
@client
end
def api
return @api if @api
# Load cached discovered API, if it exists. This prevents retrieving the
# discovery document on every run, saving a round-trip to API servers.
if File.exists? CACHED_API_FILE
File.open(CACHED_API_FILE) do |file|
@api = Marshal.load(file)
end
else
@api = client.discovered_api('analytics', API_VERSION)
File.open(CACHED_API_FILE, 'w') do |file|
Marshal.dump(@api, file)
end
end
@api
end
def profiles
client.execute(
api_method: api.management.profiles.list,
parameters: { accountId: "~all", webPropertyId: "~all" } )
end
def print_profiles
profiles.data.items.each do |profile|
printf "%-15d %-15s %s\n", profile.id, profile.webPropertyId, profile.websiteUrl
end
end
def query_template( profile_id, start_date = nil, end_date = nil )
today = Time.now.strftime( "%Y-%m-%d" )
{
"ids" => "ga:#{profile_id}",
"start-date" => start_date || today,
"end-date" => end_date || today,
"sort" => "-ga:pageviews",
"dimensions" => "ga:pageTitle",
"metrics" => "ga:pageviews,ga:newUsers,ga:users"
}
end
def hotcontent( profile_id, start_date = nil, end_date = nil )
query = query_template( profile_id, start_date, end_date )
client.execute(
api_method: api.data.ga.get,
parameters: query
)
end
def referers( profile_id, start_date = nil, end_date = nil )
query = query_template( profile_id, start_date, end_date )
query["dimensions"] = "ga:source,ga:referralPath,ga:medium"
client.execute(
api_method: api.data.ga.get,
parameters: query
)
end
def content_referers( profile_id, start_date = nil, end_date = nil )
query = query_template( profile_id, start_date, end_date )
query["dimensions"] = "ga:landingPagePath,ga:source,ga:referralPath,ga:medium"
query["sort"] = "ga:landingPagePath,-ga:pageviews"
client.execute(
api_method: api.data.ga.get,
parameters: query
)
end
def timeline( profile_id )
one_month_ago = Time.now - 30 * 24 * 60 * 60
start_date = one_month_ago
today = Time.now
seen = {}
title = {}
while start_date.to_date <= today.to_date
puts
puts start_date.to_date
contents = hotcontent( profile_id, start_date.strftime( "%Y-%m-%d" ), start_date.strftime( "%Y-%m-%d" ) )
contents.data.rows.each do |content|
unless title[content[0]]
puts " Posted: #{content[0]}"
end
title[content[0]] = true
end
puts
result = referers( profile_id, start_date.strftime( "%Y-%m-%d" ), start_date.strftime( "%Y-%m-%d" ) )
result.data.rows.each do |data|
url = data[0]
url = "http://#{data[0]}#{data[1]}" if data[2] == 'referral'
printf " %-10s %5s %s\n", data[2], data[3],url if !seen[url] && data[3].to_i > 2
seen[url] = true if data[2] == 'referral'
end
start_date = start_date + 24 * 60 * 60
end
end
def print_query_result( r )
headers = r.data.columnHeaders.collect { |x| x.name }
puts Hirb::Helpers::AutoTable.render(r.data.rows, headers: headers )
end
def print_csv_result(r)
csv_string = CSV.generate do |csv|
csv << r.data.columnHeaders.collect { |x| x.name }
r.data.rows.each do |row|
csv << row
end
end
puts csv_string
csv_string
end
end
class HammerOfTheGods < Thor
desc "profiles", "List Account Profiles"
def profiles
client.print_profiles
end
desc "hotcontent PROFILE_ID", "Show hot content for profile id"
options [:today, :yesterday, :recently, :month, :table, :csv]
def hotcontent( profile_id )
result = client.hotcontent( profile_id, start_date, end_date )
print_result result
end
desc "referers PROFILE_ID", "Show hot content for profile id"
options [:today, :yesterday, :recently, :month, :table, :csv]
def referers( profile_id )
result = client.referers( profile_id, start_date, end_date )
print_result( result )
end
desc "content_referers PROFILE_ID", "Show hot content for profile id"
options [:today, :yesterday, :recently, :month, :table, :csv]
def content_referers( profile_id )
result = client.content_referers( profile_id, start_date, end_date )
print_result( result )
end
desc "timeline PROFILE_ID", "Show a timeline of referers"
def timeline( profile_id )
client.timeline( profile_id )
end
private
def client
@client ||= AnalyticsClient.new
end
def start_date
return (Time.now - (24*60*60)).strftime( "%Y-%m-%d" ) if options[:yesterday]
return (Time.now - (7*24*60*60)).strftime( "%Y-%m-%d" ) if options[:recently]
return (Time.now - (30*24*60*60)).strftime( "%Y-%m-%d" ) if options[:month]
nil
end
def end_date
return (Time.now - (24*60*60)).strftime( "%Y-%m-%d" ) if options[:yesterday]
nil
end
def print_result( result )
if options[:csv]
client.print_csv_result( result )
else
client.print_query_result( result )
end
end
end
if __FILE__ == $0
HammerOfTheGods.start(ARGV)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment