每次使用 YouTube Data API v3 时如何绕过输入验证码来授权我的代码

Posted

技术标签:

【中文标题】每次使用 YouTube Data API v3 时如何绕过输入验证码来授权我的代码【英文标题】:How to bypass entering authentication code to authorize my code everytime I use the YouTube Data API v3 【发布时间】:2021-02-19 10:57:01 【问题描述】:

因此,每次我运行我的代码时,它都会在我的终端上提供一个链接,我必须手动按下该链接并在浏览器上选择我的 Gmail 帐户才能登录并接收授权码。我必须再次粘贴到我的终端上。

有没有办法跳过这个过程?

我正在使用的代码:

# -*- coding: utf-8 -*-

# Sample Python code for youtube.videos.update
# See instructions for running these code samples locally:
# https://developers.google.com/explorer-help/guides/code_samples#python

import os

import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors

scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]

def main():
    # Disable OAuthlib's HTTPS verification when running locally.
    # *DO NOT* leave this option enabled in production.
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

    api_service_name = "youtube"
    api_version = "v3"

    client_secrets_file = "client_secret_key.json"

    # Get credentials and create an API client
    flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
        client_secrets_file, scopes)
    credentials = flow.run_console()
    youtube = googleapiclient.discovery.build(
        api_service_name, api_version, credentials=credentials)

    request = youtube.videos().update(
        part="id,snippet",
        body=
          "id": "videoid",
          "snippet": 
            "title": "XOXOXO",
            "description": "Through IDE",
            "categoryId": "27"
          
        
    )
    response = request.execute()

    print(response)

if __name__ == "__main__":
    main()

【问题讨论】:

【参考方案1】:

确实有可能在第一次成功运行 OAuth 授权/身份验证流程时保存您的 credentials 对象;然后在每次运行程序第n-th 次时从该文件加载凭据对象,其中n >= 2

以下是我推荐的代码结构:

import os, pickle

from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build

def pickle_file_name(
        api_name = 'youtube',
        api_version = 'v3'):
    return f'token_api_name_api_version.pickle'

def load_credentials(
        api_name = 'youtube',
        api_version = 'v3'):
    pickle_file = pickle_file_name(
        api_name, api_version)

    if not os.path.exists(pickle_file):
        return None

    with open(pickle_file, 'rb') as token:
        return pickle.load(token)

def save_credentials(
        cred, api_name = 'youtube',
        api_version = 'v3'):
    pickle_file = pickle_file_name(
        api_name, api_version)

    with open(pickle_file, 'wb') as token:
        pickle.dump(cred, token)

def create_service(
        client_secret_file, scopes,
        api_name = 'youtube',
        api_version = 'v3'):
    print(client_secret_file, scopes,
        api_name, api_version,
        sep = ', ')

    cred = load_credentials(api_name, api_version)

    if not cred or not cred.valid:
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                    client_secret_file, scopes)
            cred = flow.run_console()

    save_credentials(cred, api_name, api_version)

    try:
        service = build(api_name, api_version, credentials = cred)
        print(api_name, 'service created successfully')
        return service
    except Exception as e:
        print(api_name, 'service creation failed:', e)
        return None

def main():
    youtube = create_service("client_secret_key.json",
        ["https://www.googleapis.com/auth/youtube.force-ssl"])
    if not youtube: return

    request = youtube.videos().update(
        part="id,snippet",
        body=
          "id": "videoid",
          "snippet": 
            "title": "XOXOXO",
            "description": "Through IDE",
            "categoryId": "27"
          
        
    )
    response = request.execute()

    print(response)

if __name__ == '__main__':
    main()

您必须注意上述代码的以下特点:如果您第二次从与第一次运行的目录不同的目录中运行脚本,则脚本将重新启动 OAuth当该(当前)目录不包含凭据泡菜文件时流动。


现在,如果您已经安装(或愿意安装)软件包 Google Authentication Library for Python、google-auth,版本 >= 1.21.3(google-auth v1.3.0 引入 Credentials.from_authorized_user_file,v1.8.0 引入 @ 987654330@ 和 v1.21.3 修复了后一个函数 wrt 其类的 expiry 成员),然后您可以将您的 credentials 对象保存到 JSON 文本文件并从中加载。

下面是执行此操作的代码:

import os, json, io

...

def json_file_name(
        api_name = 'youtube',
        api_version = 'v3'):
    return f'token_api_name_api_version.json'

def load_credentials(
        api_name = 'youtube',
        api_version = 'v3'):
    cred_file = json_file_name(
        api_name, api_version)

    if not os.path.exists(cred_file):
        return None

    from google.oauth2.credentials import Credentials
    return Credentials.from_authorized_user_file(cred_file)

def save_credentials(
        cred, api_name = 'youtube',
        api_version = 'v3'):
    cred_file = json_file_name(
        api_name, api_version)

    with io.open(cred_file, 'w', encoding = 'UTF-8') as json_file:
        json_file.write(cred.to_json())

...

【讨论】:

谢谢@stvar!在Youtube Analytics API...上,我在deepnote 笔记本中成功使用了您的第一个解决方案...我刷新了内核,它仍然有效。根据您的评论“您必须了解以下特性......”生成的 .pickle 文件是否会永久(或至少在出现其他随机技术问题之前一段时间)或可能由于在几小时或几天内到期,它无法工作。我的目标是每天刷新并将数据发送到数据库。我想我明天打开我的 deepnote 笔记本时会看看它是否仍然可以在没有登录的情况下工作。 @David Erickson:存储的凭据(JSON 格式的 pickle 格式)在某些情况下确实会过期,这意味着您必须再次运行 OAuth 流程。具体来说,一个此类数据包中包含的 刷新令牌 可能会过期。这是此问题的官方规范:Refresh token expiration。请注意,发布状态为 Testing 的应用的刷新令牌的生命周期仅为 7 天。 谢谢@stvar。这些是我设置的确切设置。 A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days. Youtube Analytics API 要求您使用 OAuth 并且是我们当前获取收入数据的唯一地方,因此您不能使用服务帐户或 API 密钥。我希望它们的持续时间超过 7 天,但这是有用的信息。

以上是关于每次使用 YouTube Data API v3 时如何绕过输入验证码来授权我的代码的主要内容,如果未能解决你的问题,请参考以下文章