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での私の認証は次のようになります。
pydriveを使用するたびに認証する必要がないようにするにはどうすればよいですか?
python pydriveスクリプトを使用したスクリプトが、現在ではなくsecret_client.json
を生成したアカウントにのみアップロードするように自動認証を許可する方法インターネットブラウザのログオンアカウント?
まず、あなたはこれがどのように機能するかについての非常に重要なビットを誤解しています:
別のアカウントにログインしているときに上記のスクリプトを使用しようとすると。 secret_client.jsonを生成したgdriveにeng.txtをアップロードするのではなく、認証を許可するときにログインしたアカウントをアップロードします
これはまさにそれが動作するはずです。開発者として、あなたはclient_secret.json
をアプリケーションとともに配布し、そのファイルはPyDriveがアプリケーションをGoogleで認証するために使用します。 Googleは、さまざまな理由(メトリック、アカウントへの課金、アクセスの取り消しなど)のために、各アプリケーションによって行われているAPIリクエストの数を知りたいので、アプリケーションが自身を認証する必要があります。
これで、アプリケーションがLocalWebserverAuth
を実行すると、Googleでclientが認証されます。もちろん、クライアントは実際にアプリケーションを使用している人です。この場合、開発者とクライアントは同じ人物(あなた)ですが、数百万人のユーザーにアプリケーションを配布したいと考えています。それらはすべてclient_secret.json
を提供したあなた(開発者)に持ち込まれるのではなく、自分自身を認証し、自分のドライブアカウントにファイルをアップロードできる必要があります。
ただし、アプリを実行するたびにクライアントに認証を要求する必要がないようにするための変更は、実際には非常に小さな変更にすぎません。 LoadCredentialsFile
と SaveCredentialsFile
を使用するだけです。
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')
別の方法は、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ファイルが作業ディレクトリに生成されます。
サーバーでスクリプトを自動化しようとする場合、この方法はより効果的です。
このスレッド全体が私を大いに助けてくれましたが、ここで紹介したすべてのソリューションを実装した後、もう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)
皆さん、ありがとうございました!
資格情報が設定されていない場合、このコードは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')
これは、@ 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 でこれについてもう少し詳しく説明しました。