以下是故事:
我使用Pentaho Kettle通过简单API访问从Google Analytics查询网络统计信息。对于此请求,我需要API密钥。现在这个API密钥时不时变为无效(我不确定rythm是什么)然后请求失败当然。所以我想生成一个新的,接收它并使其可用于ETL作业及其GA步骤。
我的计划是通过User Defined Java Class和google-api-java-client在一个或多个“Service Account”步骤中嵌入Java来实现此目的。 Kettle作业生成一个新的API密钥,接收它并通过字段或直接作为参数提供API密钥。
但主要是我对所描述的用例的一般Java解决方案感兴趣。如果有人有一个更好的解决方案,但我提到这些细节主要是为了将问题放到一个背景中。
问题:如何为Google Analytics简单API访问生成新的API密钥,并通过OAuth2使用google-api-java-client接收它,而无需用户交互(完全自动化)?< / p>
Bounty :我很感激答案提供Java程序或详细的API调用序列。该程序的输出是一个适用于简单API访问的功能API密钥。鉴于所涉及的预期工作,我选择了尽可能高的赏金。
我注册了一个服务帐户,所以我有以下ID和有限公司:
的client_secrets.json:
{"web":{
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"client_email": "123@developer.gserviceaccount.com",
"client_x509_cert_url":"https://www.../123@developer.gserviceaccount.com",
"client_id": "123.apps.googleusercontent.com",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"
}}
答案 0 :(得分:2)
代码之前的一些事情:
从技术上讲,如果您使用OAuth 2.0进行身份验证,那么Simple API访问根本不适用。因此您无需担心API密钥。 Pentaho的说明是旧的,除非您使用非OAuth 2.0身份验证机制(这不是您应该做的),否则不适用
您最想要使用的是用于身份验证的服务帐户,不需要任何人工干预。
注册应用
如果您尚未使用Google Cloud Console注册申请,请在云端控制台中设置项目和应用程序。系统将指导您完成选择或创建项目以及注册新应用程序的过程,并自动为您激活API。
如果您已使用Cloud Console注册了应用程序,请改为使用此过程:
转到Google Cloud Console。 选择一个项目。 在左侧边栏中,选择API&amp; AUTH。在显示的API列表中,确保将Analytics API状态设置为ON。 在左侧边栏中,选择已注册的应用。 选择一个应用程序 在任何一种情况下,您都会在应用程序的凭据页面上结束。
要设置服务帐户,请展开“证书”部分。然后选择Generate Certificate。 (如果您已有证书,则可以通过选择“生成新密钥”来添加新密钥。)将出现一个对话框。选择下载私钥以继续。下载完成后,选择查看公钥。
下载文件并关闭对话框后,您将能够获得服务帐户的电子邮件地址。
下载用于分析的Java客户端库
访问https://developers.google.com/api-client-library/java/apis/analytics/v3
转到底部的将库添加到您的项目部分,然后下载适用于Java的Google AnalyticsAPI v3客户端库。
将服务帐户电子邮件添加到GA帐户
将服务帐户电子邮件添加到您要通过API访问的Google Analytics帐户。
获取访问次数的Java应用示例
以下代码段适用于Core Reporting API。它使用服务帐户进行身份验证。然后,它会检索Google Analytics配置文件的访问次数并输出该号码。
要使用此功能,您显然应该替换服务帐户电子邮件和私钥文件的路径。您还需要从libs文件夹导入用于分析的Java客户端和相关的JARS。
另请参阅Google Analytics Core Reporting API docs了解如何使用维度和指标,细分,过滤器等查询API。
您应该可以对其进行自定义,以便与您的应用程序一起使用。
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.HashSet;
import java.util.Set;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.analytics.Analytics;
import com.google.api.services.analytics.AnalyticsScopes;
import com.google.api.services.analytics.model.GaData;
public class AnalyticsSample {
private static final String APPLICATION_NAME = "APP_NAME";
private static final String SERVICE_ACCOUNT_EMAIL = "<YOUR_SERVICE_ACCOUNT_EMAIL>@developer.gserviceaccount.com";
/** Path to the Service Account's Private Key file */
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/-privatekey.p12";
private static Analytics service;
public static Analytics getAnalyticsService() throws GeneralSecurityException, IOException {
Set<String> scopes = new HashSet<String>();
scopes.add(AnalyticsScopes.ANALYTICS_READONLY); // You can set other scopes if needed
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(scopes)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
Analytics service = new Analytics.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential)
.setApplicationName(APPLICATION_NAME)
.build();
return service;
}
public static void main(String[] args) {
try {
service = getAnalyticsService();
GaData result = service.data().ga().get(
"ga:<YOUR PROFILE ID>",
"2013-10-16", // Start date
"2013-10-17", // End Date
"ga:visits").execute(); // Add Dimensions and metrics
System.out.println(result.getRows().get(0).get(0)); // Just an example of output
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (GeneralSecurityException e) {
System.err.println(e.getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(1);
}
}
答案 1 :(得分:1)
我不是Java人,但我正在做的就是你要求使用Go和Google API。我可以给你一个关于这个过程的概述,希望这有助于/向你发送正确的方向吗? :)
概述:
编辑:不需要钥匙再生。令牌持续1小时,无法刷新。但这并不重要,因为下次使用密钥进行身份验证时,您将获得一个持续一小时的新令牌。
编辑2:我正在使用docs / pre-reqs / comments包括干净的编译Go代码。希望这会有所帮助!
package main
// overview of crqs.go:
// this example app and supporting documentation enables you to query analytics data via the Core Reporting API in a completely headless manner, with
// no "popup" or user intervention required. it doesn't "handle" the returned data very well, as that will depend on what metrics/dimensions your
// query has. better handling of this is left as an exercise for the reader. :) follow the pre-reqs, change the ga* consts specific to your own app,
// and you should be good to go. uses google-api-go-client, analytics/v3, oauth, and oauth/jwt which you can download and install from
// https://code.google.com/p/goauth2/ and http://code.google.com/p/google-api-go-client/
// docs/pre-reqs:
// 1. create a Project within the Google Cloud Console (https://cloud.google.com/console#/project)
// 2. within that Project, ensure you've turned on the Analytics API (APIs & Auth --> Analytics --> On)
// 3. within that Project, create an application of type "Web Application" (APIs & Auth --> Registered Apps)
// 4. click on the application name. expand the "Certificate" section. you will see that the email/public keys
// have not been generated. click "Generate". download the private key (.p12 file). also, note the private key password, and
// the email address, you will need these later. you will set the string const gaServiceAcctEmail to this email address.
// 5. download the JSON file, too. you will set the const gaServiceAcctSecretsFile to the location of this file.
// 6. now we need to convert the .p12 key to a PEM key. in a unix shell:
// $ openssl pkcs12 -in privatekeyfilename.p12 -nodes -nocerts > privatekeyfilename.pem
// it will ask you for the Import password. enter the private key password you were given in step 4. you should see
// "MAC verified OK", and you will have the PEM key. you will set the const gaServiceAcctPEMKey to the location of this file.
// 7. goto Google Analytics. in Admin section specific to the GA account/property you wish to query, give Read & Analyze permissions to the
// email address you were given in step 4.
// 8. now we need the Table ID of the GA account/property mentioned in step 7. login to the Google Analytics Query Explorer 2 at
// http://ga-dev-tools.appspot.com/explorer/ then select the appropriate account/property/profile in the dropdown menus. you will see
// the Table ID in the "*ids" box. it looks like "ga:1234556". you will set the string const gaTableID to this value.
// 9. that should be all you need to do! compile and "go".
// example runs:
// 1. shows total pageview count for all URLs (starting at default date october 1st through today).
// $ ./crqs
// gaStartDate=2013-10-01, gaEndDate=2013-10-18
// gaMetrics=ga:pageviews
// gaFilter=ga:pagePath=~^/
// len(gaData.Rows)=1, TotalResults=1
// row=0 [25020179]
//
// 2. shows unique pageview count per URL for top 5 URLs starting in "/movies" (starting at default date october 1st through today),
// in descending order.
// $ ./crqs -m=ga:uniquePageviews -d=ga:pagePath -s=-ga:uniquePageviews -f=ga:pagePath=~^/movies -x=5
// gaStartDate=2013-10-01, gaEndDate=2013-10-18
// gaMetrics=ga:uniquePageviews
// gaDimensions=ga:dimensions=ga:pagePath
// gaSortOrder=ga:sort=-ga:uniquePageviews
// gaFilter=ga:pagePath=~^/movie
// len(gaData.Rows)=5, TotalResults=10553
// row=0 [/movies/foo 1005697]
// row=1 [/movies/bar 372121]
// row=2 [/movies/baz 312901]
// row=3 [/movies/qux 248761]
// row=4 [/movies/xyzzy 227286]
//
// 3. shows unique pageview count per URL for top 5 URLs from Aug 1 --> Sep 1, in descending order.
// $ ./crqs -sd=2013-08-01 -ed=2013-09-01 -m=ga:uniquePageviews -d=ga:pagePath -s=-ga:uniquePageviews -x=5
// gaStartDate=2013-08-01, gaEndDate=2013-09-01
// gaMetrics=ga:uniquePageviews
// gaDimensions=ga:dimensions=ga:pagePath
// gaSortOrder=ga:sort=-ga:uniquePageviews
// len(gaData.Rows)=5, TotalResults=159023
// row=0 [/ 4280168]
// row=1 [/foo 2504679]
// row=2 [/bar 1177822]
// row=3 [/baz 755705]
// row=4 [/xyzzy 739513]
import (
"code.google.com/p/goauth2/oauth"
"code.google.com/p/goauth2/oauth/jwt"
"code.google.com/p/google-api-go-client/analytics/v3"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"
)
// constants
const (
// don't change these
dateLayout string = "2006-01-02" // date format that Core Reporting API requires
// change these! add in your own app and analytics-property-specific values
gaServiceAcctEmail string = "your-applications-email-address@developer.gserviceaccount.com" // email address of registered application
gaServiceAcctSecretsFile string = "/path/to/client_secret_your-application.apps.googleusercontent.com.json" // registered application JSON file downloaded from Google Cloud Console
gaServiceAcctPEMKey string = "/path/to/your-applications-converted-privatekey.pem" // private key (PEM format) of registered application
gaScope string = "https://www.googleapis.com/auth/analytics.readonly" // oauth 2 scope information for Core Reporting API
gaTableID string = "ga:12345678" // namespaced profile ID of the analytics account/property/profile from which to request data
)
// globals
var (
// vars for the runtime flags
gaDimensions string
gaEndDate string
gaFilter string
gaMetrics string
gaMaxResults int64
gaSortOrder string
help bool
gaStartDate string
)
// types
// struct to read the registered application's JSON secretsfile into
type GAServiceAcctSecretsConfig struct {
ClientEmail string `json:"client_email"`
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RedirectURIs []string `json:"redirect_uris"`
Scope string
AuthURI string `json:"auth_uri"`
TokenURI string `json:"token_uri"`
}
// func: init()
// initialisation function for the command line flags/options.
func init() {
flag.BoolVar(&help, "h", false, "Show all command line arguments.")
flag.StringVar(&gaDimensions, "d", "", "GA query dimensions")
flag.StringVar(&gaEndDate, "ed", "", "GA query end date")
flag.StringVar(&gaFilter, "f", "", "GA filter to apply")
flag.Int64Var(&gaMaxResults, "x", 10000, "GA maximum # of results to return (default: 10000)")
flag.StringVar(&gaMetrics, "m", "ga:pageviews", "GA metrics you want to query (default: ga:pageviews)")
flag.StringVar(&gaSortOrder, "s", "", "GA query reply sort order")
flag.StringVar(&gaStartDate, "sd", "2013-10-01", "GA query start date (default: 2013-10-01)")
}
// func: readConfig()
// reads in the registered application's JSON secretsfile and crafts an oauth.Config which
// it returns to the calling func. exits hard if either the JSON secretsfile load fails,
// or if the unmarshal fails.
func readGAServiceAcctSecretsConfig() *oauth.Config {
configfile := new(GAServiceAcctSecretsConfig)
data, err := ioutil.ReadFile(gaServiceAcctSecretsFile)
if err != nil {
log.Fatal("error reading GA Service Account secret JSON file -", err)
}
err = json.Unmarshal(data, &configfile)
if err != nil {
log.Fatal("error unmarshalling GA Service Account secret JSON file -", err)
}
return &oauth.Config{
ClientId: configfile.ClientId,
ClientSecret: configfile.ClientSecret,
Scope: gaScope,
AuthURL: configfile.AuthURI,
TokenURL: configfile.TokenURI,
}
} //
// func: main()
// the main function. duh.
func main() {
// grok the command line args
flag.Usage = usage
flag.Parse()
if help {
flag.Usage()
}
// read in the registered application's JSON secretsfile and get an oauth.Config in return.
oauthConfig := readGAServiceAcctSecretsConfig()
// read in the registered applications private PEM key.
pemKey, err := ioutil.ReadFile(gaServiceAcctPEMKey)
if err != nil {
log.Fatal("error reading GA Service Account PEM key -", err)
}
// create a JWT (JSON Web Token).
jsonWebToken := jwt.NewToken(gaServiceAcctEmail, oauthConfig.Scope, pemKey)
// form the JWT claim set.
jsonWebToken.ClaimSet.Aud = oauthConfig.TokenURL
// create a basic httpclient. we will use this to send the JWT.
httpClient := &http.Client{}
// build the request, encode it, and then send the JWT. we get a nifty oauth.Token in return.
oauthToken, err := jsonWebToken.Assert(httpClient)
if err != nil {
log.Fatal("error asserting JSON Web Token -", err)
}
// build the oauth transport
oauthTransport := oauth.Transport{Config: oauthConfig}
// set the oauthTransport's token to be the oauthToken
oauthTransport.Token = oauthToken
// create a new analytics service by passing in the httpclient returned from Client() that can now make oauth-authenticated requests
analyticsService, err := analytics.New(oauthTransport.Client())
if err != nil {
log.Fatal("error creating Analytics Service -", err)
}
// create a new analytics data service by passing in the analytics service we just created
dataGaService := analytics.NewDataGaService(analyticsService)
// w00t! now we're talking to the core reporting API. hard stuff over, let's do a simple query.
// if no gaEndDate specified via command line args, set it to today's date.
if gaEndDate == "" {
t := time.Now()
gaEndDate = t.Format(dateLayout)
}
// print the query start & end dates.
fmt.Printf("gaStartDate=%s, gaEndDate=%s\n", gaStartDate, gaEndDate)
fmt.Printf("gaMetrics=%s\n", gaMetrics)
// setup the query
dataGaGetCall := dataGaService.Get(gaTableID, gaStartDate, gaEndDate, gaMetrics)
// setup the dimensions (if any).
if gaDimensions != "" {
dimensions := fmt.Sprintf("ga:dimensions=%s", gaDimensions)
fmt.Printf("gaDimensions=%s\n", dimensions)
dataGaGetCall.Dimensions(gaDimensions)
}
// setup the sort order (if any).
if gaSortOrder != "" {
sortorder := fmt.Sprintf("ga:sort=%s", gaSortOrder)
fmt.Printf("gaSortOrder=%s\n", sortorder)
dataGaGetCall.Sort(gaSortOrder)
}
// setup the filter (if any).
if gaFilter != "" {
filter := fmt.Sprintf("%s", gaFilter)
fmt.Printf("gaFilter=%s\n", filter)
dataGaGetCall.Filters(filter)
}
// setup the max results we want returned.
dataGaGetCall.MaxResults(gaMaxResults)
// send the query to the API, get gaData back.
gaData, err := dataGaGetCall.Do()
if err != nil {
log.Fatal("API error -", err)
}
// how much data did we get back?
fmt.Printf("len(gaData.Rows)=%d, TotalResults=%d\n", len(gaData.Rows), gaData.TotalResults)
// a lazy loop through the returned rows
for row := 0; row <= len(gaData.Rows)-1; row++ {
fmt.Printf("row=%d %v\n", row, gaData.Rows[row])
}
}
// func: usage()
// prints out all possible flags/options when "-h" or an unknown option is used at runtime.
// exits back to shell when complete.
func usage() {
fmt.Printf("usage: %s [OPTION] \n", os.Args[0])
flag.PrintDefaults()
os.Exit(2)
}