2

这是故事:

我使用 Pentaho Kettle 通过 Simple API Access 从 Google Analytics 查询网络统计数据。对于这个请求,我需要 API 密钥。现在这个 API 密钥不时变为无效(我不确定节奏是什么),然后请求当然会失败。所以我想生成一个新的,接收它并使其可用于 ETL 作业及其 GA 步骤。

我的计划是通过google-api-java-clientService Account嵌入一个或多个“用户定义的 Java 类”步骤中的 Java 来执行此操作。Kettle 作业生成一个新的 API 密钥,接收它并通过字段或直接作为参数提供 API 密钥。

我主要对所描述用例的通用 Java 解决方案感兴趣。如果有人有一个更好的水壶解决方案,但我提到这些细节主要是为了将问题置于上下文中。

问题:如何为 Google Analytics Simple API Access 生成一个新的 API 密钥,并通过 OAuth2 使用 google-api-java-client 接收它,而无需用户交互(完全自动化)?

赏金:如果提供 Java 程序或 API 调用的详细序列,我将不胜感激。该程序的输出是适用于简单 API 访问的有效 API 密钥。鉴于所涉及的预期工作,我选择了尽可能高的赏金。


我注册了一个服务帐户,因此我有以下可用的 ID 和公司:

  • 客户编号
    • 123.apps.googleusercontent.com
  • 电子邮件地址
    • 123@developer.gserviceaccount.com
  • 公钥指纹
    • abcxxx
  • client_secrets.json
    • {...}
  • 私钥
    • abcxxx-privatekey.p12

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"
}}
4

2 回答 2

2

代码之前的几件事:

  1. 从技术上讲,如果您使用 OAuth 2.0 进行身份验证,那么简单 API 访问根本不适用。所以你不需要担心 API Key。Pentaho 的说明很旧,除非您使用非 OAuth 2.0 身份验证机制,否则不适用(这不是您应该做的)

  2. 您最喜欢使用的是不需要任何人工交互的身份验证服务帐户。

注册应用程序

如果您尚未在 Google Cloud Console 中注册您的应用程序,请在 Cloud Console 中设置项目和应用程序。系统会引导您完成选择或创建项目和注册新应用程序的过程,并自动为您激活 API。

如果您已经在 Cloud Console 中注册了您的应用,请改为按照以下步骤操作:

转到谷歌云控制台。选择一个项目。在左侧边栏中,选择 APIs & auth。在显示的 API 列表中,确保 Analytics API 状态设置为开启。在左侧边栏中,选择已注册的应用程序。选择一个应用程序。无论哪种情况,您最终都会进入应用程序的凭据页面。

要设置服务帐户,请展开证书部分。然后选择生成证书。(如果您已经有一个证书,您可以通过选择 Generate New Key 添加一个新密钥。)出现一个对话框;选择下载私钥继续。下载完成后,选择查看公钥。

下载文件并关闭对话框后,您将能够获取服务帐户的电子邮件地址。

下载用于分析的 Java 客户端库

访问https://developers.google.com/api-client-library/java/apis/analytics/v3

转到底部的将库添加到您的项目部分并下载适用于 Java 的 Google Analytics API v3 客户端库。

将服务帐户电子邮件添加到 GA 帐户

将服务帐户电子邮件添加到您要使用 API 访问的 Google Analytics(分析)帐户。

获取访问次数的示例 Java 应用程序

以下代码片段适用于 Core Reporting API。它使用服务帐户进行身份验证。然后它检索分析配置文件的访问并输出数字。

要使用它,您显然应该替换服务帐户电子邮件和私钥文件的路径。您还需要从 libs 文件夹中导入用于分析的 Java 客户端和相关的 JARS。

另请参阅Google Analytics Core Reporting API 文档以了解使用维度和指标、细分、过滤器等查询 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);
     }

}
于 2013-10-19T02:31:32.660 回答
1

我不是 Java 人,但我所做的几乎完全符合您使用 Go 和 Google API 的要求。我可以给你一个过程的概述,希望这有助于/向你发送正确的方向?:)

概述:

  • 从您在谷歌云控制台中注册的应用程序下载证书
  • 将证书从 PCS12 编码转换为 PEM
  • 使用该密钥以及电子邮件地址(foobarbazxxxxetc@developer.gserviceaccount.com 之一)和您要使用的 API 范围来制作 JWT(JSON Web 令牌)
  • 将具有适当权限的相同电子邮件地址添加到您要使用的分析帐户
  • 使用 JWT 获取 oauth 令牌
  • 创建分析服务,使用 oauth 令牌进行身份验证
  • 现在您可以使用核心报告 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)
}
于 2013-10-18T01:08:48.280 回答