web-dev-qa-db-ja.com

pydrive検証プロセスの自動化

GoogleAuthライブラリを使用するときにpydriveプロセスを自動化しようとしています( https://pypi.python.org/pypi/PyDrive )。

secret_client.jsonが機能するようにpydriveとgoogle APIを設定しましたが、スクリプトを実行するたびにgdriveにアクセスするにはWeb認証が必要です。

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を生成したgdriveにsecret_client.jsonをアップロードするのではなく、認証を許可するときにログインしたアカウントをアップロードします

前回の投稿から、検証プロセスを自動化するために次のことを試みましたが、エラーメッセージが表示されています。

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を使用するたびに認証する必要がないようにするにはどうすればよいですか?

python pydriveスクリプトを使用したスクリプトが、現在ではなくsecret_client.jsonを生成したアカウントにのみアップロードするように自動認証を許可する方法インターネットブラウザのログオンアカウント?

45
alvas

まず、あなたはこれがどのように機能するかについての非常に重要なビットを誤解しています:

別のアカウントにログインしているときに上記のスクリプトを使用しようとすると。 secret_client.jsonを生成したgdriveにeng.txtをアップロードするのではなく、認証を許可するときにログインしたアカウントをアップロードします

これはまさにそれが動作するはずです。開発者として、あなたはclient_secret.jsonをアプリケーションとともに配布し、そのファイルはPyDriveがアプリケーションをGoogleで認証するために使用します。 Googleは、さまざまな理由(メトリック、アカウントへの課金、アクセスの取り消しなど)のために、各アプリケーションによって行われているAPIリクエストの数を知りたいので、アプリケーションが自身を認証する必要があります。

これで、アプリケーションがLocalWebserverAuthを実行すると、Googleでclientが認証されます。もちろん、クライアントは実際にアプリケーションを使用している人です。この場合、開発者とクライアントは同じ人物(あなた)ですが、数百万人のユーザーにアプリケーションを配布したいと考えています。それらはすべて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')
80
dano

別の方法は、setting.yamlファイルを作業ディレクトリに書き込むことにより、カスタム認証フローを使用することです。また、LocalWebserverAuth()は1時間で期限切れになるトークンを生成し、更新トークンがないため、このメソッドはより適切に機能します。

サンプルの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ファイルが作業ディレクトリに生成されます。

サーバーでスクリプトを自動化しようとする場合、この方法はより効果的です。

9
wang892

このスレッド全体が私を大いに助けてくれましたが、ここで紹介したすべてのソリューションを実装した後、もう1つの問題が発生しました。LocalWebserverAuth()はrefresh tokenを取得しません。

@danoのコードを実装した後に生成された「mycreds.txt」を開くと、「refresh token」が「null」に設定されていることがわかります。数時間後、トークンの有効期限が切れ、次のメッセージが表示され、手動で再度認証する必要があります。

エラー:

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

そのための解決策は、GoogleAuthのフローパラメーターで承認_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
tetodenega

資格情報が設定されていない場合、このコードは2つのオプションを持つ入力ボックスを生成します。

  • ブラウザ認証(一度だけ行う必要があります)

  • 資格情報ファイルのアップロード(このファイルは、ブラウザー認証用に選択した最初の時間に生成されます

ローカル環境からmycreds.txtに保存された資格情報を使用するため、承認を要求することなく実行されるノートブックを簡単に共有できるようになりました。ただし、ランタイムがクラッシュしたりリセットされたりした場合、そのファイルは失われるため、上の入力ボックスから再度挿入する必要があります。もちろん、ブラウザー認証を介してこれを再度行うことができますが、ノートブックを使用しているユーザーにmycreds.txtを再配布する場合、ユーザーはアップロード機能を使用して資格情報をローカル環境に挿入できます。

最後の数行は、認証済みドライブからの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')
1
Ger

これは、@ wang892 上記の投稿 (コメントするのに十分な評判がありません)を完了するためです。

その答えは、スクリプトを自動化するのに役立ちました(実行するたびに再認証する必要はありません)。

しかし、サンプルのsettings.yamlファイルを使用したため、 PyDriveのドキュメントで入手可能 に問題が発生しました(oauthの動作に関する完全な無知のため)。

このサンプルファイルには次の行が含まれており、自分で作成したファイルとフォルダーのみにアクセスするようにPyDriveスクリプトを制限していると思います(詳細については PyDrive issue#122 を参照してください):

制限付きアクセス:

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

これらの行を変更すると、問題は解決しました(保存された資格情報を削除し、スクリプトを実行して再認証する必要がありました)。

これらの新しい行により、スクリプトはGoogleドライブ内のすべてのファイルにアクセスできるようになりました。

フルアクセス:

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

PyDrive issue#108 でこれについてもう少し詳しく説明しました。

1
abu