使用Python和Google APIs客户端库的理解

4
为了提高我的Python技能,我试图阅读并理解Google API Python client的源代码。
但我被卡住了,尽管我在Google上搜索过,但我仍然无法理解代码的一个特定部分是如何工作的。
我编写了一个小程序来演示该部分:

upload.py

from __future__ import print_function
import os
import httplib2

import apiclient
import oauth2client

try:
    import argparse
    flags = argparse.ArgumentParser(
        parents=[oauth2client.tools.argparser]).parse_args()
except ImportError:
    flags = None

SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'

# Enter your project name here!!
APPLICATION_NAME = 'API Project'


def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'drive-credentials.json')

    store = oauth2client.file.Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = oauth2client.client.flow_from_clientsecrets(
            CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = oauth2client.tools.run_flow(flow, store, flags)
        else:  # Needed only for compatibility with Python 2.6
            credentials = oauth2client.tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials


def main():
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())

    file_service = apiclient.discovery.build('drive', 'v3', http=http).files()

    results = file_service.get(
        fileId="0Bw239KLrN7zoWl95Nml2ZUpsNnc").execute()
    print(results)

    results = file_service.list(
        pageSize=10, fields="files(id, name)").execute()
    print(results)

if __name__ == '__main__':
    main()

在这行代码file_service = apiclient.discovery.build('drive', 'v3', http=http).files()中,我无法在库的源代码中找到files()方法的定义。我也无法找到任何被称为get()list()的方法。
我已经阅读了库的Github存储库以及其代码文档,但没有找到任何有用的信息。
以下是我迄今为止尝试过的内容:
通过查看文件discovery.py,函数build()返回build_from_document()函数的结果,后者又返回Resource()类的一个实例。
但现在遇到了死路,因为类Resource()中没有任何名为files()的方法。
那么,如何找到这些方法files()get()list()等的内部工作原理呢?

但是 Resource 类似乎有一些方法可以动态地向自身添加方法。我会从那里开始。 - Jasper
@Jasper,我对它是如何工作毫无头绪(我是Python的初学者)。你能否详细地解释一下应该从哪里开始? - Anmol Singh Jaggi
这是相关的函数吧:https://github.com/google/google-api-python-client/blob/master/googleapiclient/discovery.py#L967。添加类似"`print attr_name, value"的内容和代码,以打印堆栈跟踪(https://docs.python.org/2/library/traceback.html)(或使用您喜欢的调试器),以查看是谁在调用此函数来添加files()get()`等。 - Jasper
2个回答

2

(2017年2月)好问题!当我第一次开始尝试使用Google APIs时,我也遇到了同样的理解问题。让我简化一下你的代码。然后它应该更容易理解,我也可以将您转发到正确的文档。

您使用的授权代码现在可以通过Google APIs客户端库中的最新更新显着简化。(确保使用pip install -U google-api-python-client [或pip3用于Python 3]更新Python库。)这是一个使用list()的工作示例--您应该能够以此为灵感并重新实现您的main()使其正常运行。

# authorization boilerplate code
SCOPES = 'https://www.googleapis.com/auth/drive.readonly.metadata'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_id.json', SCOPES)
    creds = tools.run_flow(flow, store)

# call files().list() to display 1st 100 files in My Drive folder
DRIVE = discovery.build('drive', 'v3', http=creds.authorize(Http()))
files = DRIVE.files().list().execute().get('files', [])
for f in files:
    print(f['name'], f['mimeType'])

以下是我为使用Python从Drive API中获取资源(视频,博客文章等)创建的其他资源...上述代码在第一对中显示:

(*)- TL;DR:将纯文本文件上传到Drive,导入/转换为Google文档格式,然后将该文档导出为PDF。上面的文章使用了与您的代码示例类似的Drive API v2; 此后续文章描述了将其迁移到Drive API v3,这里是一个开发人员视频结合了“穷人版转换器”两篇文章。

回答您问题的第二部分,答案是:您正在使用的方法(及其文档)不是客户端库(apiclientoauth2client等)的一部分。这就是为什么您找不到任何关于它们的文档。请注意,在我上面的代码中,我从apiclient.discovery.build()创建了一个DRIVE服务端点,停在那里,而您在调用build()函数时添加了.files()

Drive服务端点是您想要保留并且不要深入*API(与您执行的操作类似,使用.files()在调用build()函数之后)。如果您将其保留在更高级别上,则可以对API进行多次调用(而不仅限于使用files()),即about().get()files().list()files().export()等。一些建议:

  1. 创建一个通用的服务端点,比如 DRIVE,然后使用 API 调用(而不是你所做的等价于 DRIVE.files() 的方式)。
  2. 正在使用的 API 的文档可以在 Drive API 文档中找到。例如,files()files().get()files().list() 等。它们并不是您所知道的 "Python 函数",而是 API 调用本身的 Python 包装器,这就是为什么您需要服务端点的原因。
  3. 以下是有关 Drive API 的 概述,供进一步阅读。

最后的提示:使用最严格的范围 -- https://www.googleapis.com/auth/drive 是完全的 Drive 读写访问权限,并且通常不必要。由于我只显示文件名和 MIME 类型,因此我只需要只读权限。你知道当你安装一个应用程序时,它会请求所有这些疯狂的权限吗?这很相似。您请求的范围越少,对应的限制越多,用户就越有可能不用担心选择你。学习 所有 Drive 范围,并找到最适合您和您的用户的范围。

请注意,我使用 storage.json 来存储我的密钥,而不是 .credentials/drive-credentials.json


0

只是在wescpy的精彩回答上做了一些补充:

当您尝试使用各种范围进行操作时,每次都需要删除那个在完成Google登录时自动创建的storage.json

在我的情况下,我正在尝试使用drive.readonly,然后想要开始上传文件drive,但是自从我上次使用readonly工作以来已经过去了很多月,我已经忘记了storage.json是如何创建的。

因此,我花了一段时间才意识到,我可以让我的脚本指向一个新的(不存在的)storage2.json来捕获drive凭据,而不是删除storage.json


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接