如何在不使用gflags的情况下获取Google Analytics凭据 - 使用run_flow()代替?

24 投票
3 回答
4997 浏览
提问于 2025-04-18 14:16

这可能需要一点时间来解释,请耐心听我说:

我正在做一个工作项目,需要获取谷歌分析的数据。我最开始是按照这个链接来操作的,所以在安装了API客户端 pip install --upgrade google-api-python-client 并设置好 client_secrets.json 之后,它要求我安装gflags才能执行 run() 这个语句。(也就是说 credentials = run(FLOW, storage)

现在,我收到了一个错误信息,提示我安装gflags,或者更好的是使用 run_flow()(具体的错误信息是):

NotImplementedError: 必须安装gflags库才能使用tools.run()。请安装gflags,或者更好地切换到使用tools.run_flow()。

几个月前我用过gflags,但它和我们的框架(pyramid)不兼容,所以我们把它删掉了,直到弄清楚问题所在。而且,之所以建议从gflags切换到 run_flow() 是因为gflags已经不再推荐使用,所以我不想再像之前那样使用它。现在我想做的是切换到使用 run_flow()

问题是 run_flow() 需要一个命令行参数,但我的应用程序并不是命令行应用。我找到了一些有用的文档,但我在构建 run_flow() 函数的参数时遇到了困难。

在展示代码之前,还有一件事需要解释。

run_flow() 需要三个参数 (文档在这里)。它和 run() 一样需要流和存储,但它还需要一个标志对象。gflags库构建了一个标志 ArgumentParser 对象,这个对象在 oauth2client 的执行方法中使用。

以下是一些在构建 argumentParser 对象时有帮助的链接:

第二个链接非常有用,可以看到它是如何执行的,所以现在当我尝试做类似的事情时,sys.argv 会拉取我正在运行的虚拟环境的位置,也就是 pserve,同时还会拉取我的 .ini 文件(这个文件存储了我机器运行虚拟环境所需的凭证)。但这会抛出一个错误,因为它期望的是其他东西,这就是我卡住的地方。

  • 我不知道需要构建什么样的标志对象来传递给 run_flow()
  • 我不知道需要传入什么样的argv参数,以便 flags = parser.parse_args(argv[1:]) 能够获取正确的信息(我不知道正确的信息应该是什么)

代码:

CLIENT_SECRETS = client_file.uri
MISSING_CLIENT_SECRETS_MESSAGE = '%s is missing' % CLIENT_SECRETS
FLOW = flow_from_clientsecrets(
    CLIENT_SECRETS,
    scope='https://www.googleapis.com/auth/analytics.readonly',
    message=MISSING_CLIENT_SECRETS_MESSAGE
)
TOKEN_FILE_NAME = 'analytics.dat'

def prepare_credentials(self, argv):
    storage = Storage(self.TOKEN_FILE_NAME)
    credentials = storage.get()

    if credentials is None or credentials.invalid:
        parser = argparse.ArgumentParser(description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter,
            parents=[tools.argparser])
        flags = parser.parse_args(argv[1:]) # i could also do just argv, both error
        credentials = run_flow(self.FLOW, storage, flags) 
    return credentials

def initialize_service(self, argv):
    http = httplib2.Http()
    credentials = self.prepare_credentials(self, argv)
    http = credentials.authorize(http)
    return build('analytics', 'v3', http=http)

我调用一个主函数,传入 sys.argv,然后调用 initialize_service

def main(self, argv):
    service = self.initialize_service(self, argv)

    try:
        #do a query and stuff here

我知道这样做不会成功,因为我的应用程序不是命令行应用,而是一个完整的集成服务,但我觉得试试看也没坏处。你有什么想法可以正确构建标志对象吗?

3 个回答

-2

可以传递的标志可以在 这里 找到,具体包括:

  --auth_host_name: Host name to use when running a local web server
    to handle redirects during OAuth authorization.
    (default: 'localhost')

  --auth_host_port: Port to use when running a local web server to handle
    redirects during OAuth authorization.;
    repeat this option to specify a list of values
    (default: '[8080, 8090]')
    (an integer)

  --[no]auth_local_webserver: Run a local web server to handle redirects
    during OAuth authorization.
    (default: 'true')

我还没弄清楚到底该怎么解析这些标志。我尝试过给这三个标志传递不同的值,但都没有成功。我在这里有一个悬赏问题 ,也许等回答出来后对你会有帮助。

0

这段代码对我使用 Gmail API 时很有效。

(这个链接也很有帮助。命令行工具

import argparse
import httplib2
from oauth2client.tools import run_flow
from oauth2client.tools import argparser
from oauth2client.file import Storage

CLIENT_SECRETS_FILE = "your_file.json"
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.readonly'

STORAGE = Storage("storage")

flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()

credentials = STORAGE.get()

if credentials is None or credentials.invalid:
    #magic 
    parser = argparse.ArgumentParser(parents=[argparser])
    flags = parser.parse_args()
    credentials = run_flow(flow, STORAGE, flags, http=http)


http = credentials.authorize(http)
gmApi = build('gmail', 'v1', http=http)
# ...
17
from oauth2client import tools

flags = tools.argparser.parse_args(args=[])
credentials = tools.run_flow(flow, storage, flags)

我花了一些时间折腾,终于解决了它让我掉进的两个陷阱:

  1. 必须使用工具里提供的argparser。
  2. 我需要给args传一个空列表,这样它就不会从命令行读取参数了,因为我是在单元测试中运行它的(所以命令行参数是不同的)。

撰写回答