自动化pydrive验证过程

时间:2014-06-25 21:49:01

标签: python google-api cloud google-drive-api pydrive

我在使用GoogleAuth库(https://pypi.python.org/pypi/PyDrive)时尝试自动执行pydrive流程。

我已经设置了pydrive和google API,以便我的secret_client.json正常工作,但每次运行我的脚本时都需要进行gdrive访问的网络身份验证:

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gauth = GoogleAuth()
gauth.LocalWebserverAuth()

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')

eng.txt只是一个文本文件。此外,当我登录到另一个帐户时,我尝试使用上面的脚本。 它不会将eng.txt上传到生成secret_client.json的gdrive中,而是将我授权身份验证时登录的帐户

在上一篇文章中,我尝试了以下操作来自动执行验证过程,但它会给出错误消息:

import base64, httplib2
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

#gauth = GoogleAuth()
#gauth.LocalWebserverAuth()

# from google API console - convert private key to base64 or load from file
id = "464269119984-j3oh4aj7pd80mjae2sghnua3thaigugu.apps.googleusercontent.com"
key = base64.b64decode('COaV9QUlO1OdqtjMiUS6xEI8')

credentials = SignedJwtAssertionCredentials(id, key, scope='https://www.googleapis.com/auth/drive')
credentials.authorize(httplib2.Http())

gauth = GoogleAuth()
gauth.credentials = credentials

drive = GoogleDrive(gauth)

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')

错误:

Traceback (most recent call last):
  File "/home/alvas/git/SeedLing/cloudwiki.py", line 29, in <module>
    textfile.Upload()
  File "/usr/local/lib/python2.7/dist-packages/pydrive/files.py", line 216, in Upload
    self._FilesInsert(param=param)
  File "/usr/local/lib/python2.7/dist-packages/pydrive/auth.py", line 53, in _decorated
    self.auth.Authorize()
  File "/usr/local/lib/python2.7/dist-packages/pydrive/auth.py", line 422, in Authorize
    self.service = build('drive', 'v2', http=self.http)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/apiclient/discovery.py", line 192, in build
    resp, content = http.request(requested_url)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 475, in new_request
    self._refresh(request_orig)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 653, in _refresh
    self._do_refresh_request(http_request)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 677, in _do_refresh_request
    body = self._generate_refresh_request_body()
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 861, in _generate_refresh_request_body
    assertion = self._generate_assertion()
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 977, in _generate_assertion
    private_key, self.private_key_password), payload)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/crypt.py", line 131, in from_string
    pkey = crypto.load_pkcs12(key, password).get_privatekey()
OpenSSL.crypto.Error: [('asn1 encoding routines', 'ASN1_get_object', 'header too long')]

我在gdrive api上的身份验证如下:

enter image description here

我如何使用pydrive,以便每次使用时都不需要进行身份验证?

如何允许自动身份验证,以便使用pydrive脚本的python脚本只会上传到生成secret_client.json的帐户,而不会上传到互联网浏览器上当前登录的帐户?

5 个答案:

答案 0 :(得分:74)

首先,你误解了一个非常重要的一点:

  

当我在登录另一个脚本时尝试使用上述脚本时   帐户。它没有将eng.txt上传到我生成的gdrive中   secret_client.json但是我登录时的帐户   授权身份验证

这正是它应该如何运作的。作为开发人员,您在应用程序中分发client_secret.json,PyDrive使用该文件向Google验证应用程序。谷歌想要知道每个应用程序有多少API请求出于各种原因(指标,收费帐户,撤销访问等),因此它需要应用程序进行身份验证。

现在,当您的应用程序运行LocalWebserverAuth时,它会使用Google对客户端进行身份验证。当然,客户是实际使用您的应用程序的人。在这种情况下,开发人员和客户是同一个人(您),但想象您希望将您的应用程序分发给数百万不同的人。他们需要能够对自己进行身份验证并将文件上传到他们自己的云端硬盘帐户,而不是让他们全部都在您的(开发人员)中,他们提供了client_secret.json

也就是说,它实际上只是一个非常小的变化,所以你的应用程序不必在每次运行应用程序时都要求客户端进行身份验证。您只需使用LoadCredentialsFileSaveCredentialsFile

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gauth = GoogleAuth()
# Try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
    # Authenticate if they're not there
    gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
    # Refresh them if expired
    gauth.Refresh()
else:
    # Initialize the saved creds
    gauth.Authorize()
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')

答案 1 :(得分:8)

另一种方法是通过将setting.yaml文件写入工作目录来使用自定义身份验证流程。此方法效果更好,因为LocalWebserverAuth()将生成一个在一小时内到期的令牌,并且没有刷新令牌。

示例settings.yaml文件如下所示

client_config_backend: file
client_config:
    client_id: <your_client_id>
    client_secret: <your_secret>

save_credentials: True
save_credentials_backend: file
save_credentials_file: credentials.json

get_refresh_token: True

oauth_scope:
    - https://www.googleapis.com/auth/drive
    - https://www.googleapis.com/auth/drive.install

使用此文件,您仍然必须使用浏览器首次完成身份验证,之后将在工作目录中使用刷新令牌生成credentials.json文件。

如果您尝试在服务器上自动化脚本

,此方法效果会更好

答案 2 :(得分:2)

整个线程对我有很大帮助,但是在实施了此处介绍的所有解决方案之后,又出现了一个问题:LocalWebserverAuth()无法获得刷新令牌

如果打开在实现@dano的代码后生成的“ mycreds.txt”,则会看到“刷新令牌”将设置为“空”。几个小时后,令牌到期,您得到以下内容,最终不得不再次手动进行身份验证。

错误:

raise RefreshError('No refresh_token found.') pydrive.auth.RefreshError: No refresh_token found.Please set access_type of OAuth to offline.

为此,解决方案是在GoogleAuth的流参数上强制rovaling_promt并将access_type设置为离线。

这是我没有更多错误的方式:

gauth = GoogleAuth()

# Try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")

if gauth.credentials is None:
    # Authenticate if they're not there

    # This is what solved the issues:
    gauth.GetFlow()
    gauth.flow.params.update({'access_type': 'offline'})
    gauth.flow.params.update({'approval_prompt': 'force'})

    gauth.LocalWebserverAuth()

elif gauth.access_token_expired:

    # Refresh them if expired

    gauth.Refresh()
else:

    # Initialize the saved creds

    gauth.Authorize()

# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")  

drive = GoogleDrive(gauth)

谢谢大家!

答案 3 :(得分:0)

如果没有适当的凭据,则此代码将生成带有两个选项的输入框:

  • 浏览器身份验证(您只需执行一次)

  • 凭据文件的上传(此文件将在您选择用于浏览器身份验证的第一时间生成

现在,可以轻松共享笔记本,因为笔记本将使用本地环境中mycreds.txt中保存的凭据,因此笔记本无需共享授权即可运行。但是,如果运行时崩溃或被重置,该文件将丢失,需要通过上面的输入框再次插入。当然,您可以通过浏览器身份验证再次执行此操作,但是如果将mycreds.txt重新分发给使用笔记本的人员,则他们可以使用Upload功能将凭据插入本地环境。

最后几行仅提供了一个示例,说明如何将经过身份验证的驱动器中的csv文件上传到笔记本中并在笔记本中使用。

#Install the required packages and fix access to my Google drive account
!pip install pydrive
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials


#Checks for file with Google authentication key, if the file is not in place, it asks to authenticate via the browser
gauth = GoogleAuth()
if os.path.isfile("mycreds.txt") is False:
    choice = input ("Do you want to: U) Upload authentication file (mycreds.txt). B) Browser authentication (only possible for owner of the connected Google drive folder). [U/B]? : ")
    if choice == "U":
          print ("Upload the mycreds.txt file")
          from google.colab import files
          files.upload()      
    elif choice == "B":
          auth.authenticate_user()
          gauth.credentials = GoogleCredentials.get_application_default()
          gauth.SaveCredentialsFile("mycreds.txt")

gauth.LoadCredentialsFile("mycreds.txt")
if gauth.access_token_expired:
    gauth.Refresh()
else: gauth.Authorize()

#Now you can easily use the files from your drive by using their ID  
drive = GoogleDrive(gauth)
download = drive.CreateFile({'id': '1KRqYpR9cteX-ZIwhdfghju6_wALl4'})
download.GetContentFile('my_data.csv')
data_frame = pd.read_csv('my_data.csv')

答案 4 :(得分:0)

这是刚刚完成@ wang892 post above(我没有足够的信誉评论)。

这答案让我(不必每次我运行它时重新进行身份验证)来自动我的脚本。

但为我所用的样品settings.yaml文件available in PyDrive documentation,我遇到了问题(由于我了解OAuth如何工作的完整的无知)。

该示例文件包含以下几行,我认为这限制了我的PyDrive脚本只能访问自身创建的文件和文件夹(有关详细信息,请参见PyDrive issue #122

受限访问权限:

$page = $request->has('page') ? $request->input('page') : 1; // Use ?page=x if given, otherwise start at 1
        $numPerPage = 15; // Number of results per page
        $count = Project::count(); // Get the total number of entries you'll be paging through
        // Get the actual items
        $projects = Project::orderBy('created_at', 'desc')
            ->take($numPerPage)->offset(($page-1)*$numPerPage)->get()->groupBy(function($project) {
                return $project->created_at->format('Y-m-d');
            });
        $data['sorted'] = new Paginator($projects, $count, $numPerPage, $page, ['path' => $request->url(), 'query' => $request->query()]);

当我更改这些行时,问题得以解决(我不得不再次删除存储的凭据并运行脚本以对其进行重新授权)。

有了这些新行,我的脚本现在可以访问我的Google云端硬盘中的所有文件了:

完全访问权限:

oauth_scope:
  - https://www.googleapis.com/auth/drive.file
  - https://www.googleapis.com/auth/drive.install

PyDrive issue #108中对此有更多了解,这使我受益匪浅。