Created
December 4, 2014 22:48
-
-
Save wschenk/d7f8650d619d8f68730a to your computer and use it in GitHub Desktop.
Scripting Google Analytics with ruby-api-client
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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