Python调用YouTube API上传视频触发违规政策被设为私密问题排查
问题现象
通过Python脚本调用YouTube API上传视频时,平台会自动将上传的视频设为私密状态,提示违反垃圾内容、欺骗性行为及诈骗相关政策;但完全相同的视频通过YouTube官方网页端上传时无任何报错,可成功发布。
可能成因
- API凭证/项目信誉问题:网页端上传走普通用户账号风控链路,只要账号完成真人验证、有正常使用记录,风控阈值很低;但API上传会额外校验绑定的Google Cloud项目状态——如果项目还处于测试阶段、未完成OAuth应用审核,或者对应凭证之前被用于批量上传低质内容,哪怕视频文件和网页端上传的完全一致,也会因为API端信誉分不足触发更严格的风控规则,直接标记违规并设为私密。
- 元数据触发垃圾内容检测:当前代码的默认标题为
Test Title、默认描述为Test Description,如果上传时没有替换成和网页端上传完全一致的标题、描述、标签、分类,这类测试占位文本是垃圾内容检测的高命中特征——大量批量发垃圾内容的自动化脚本都使用这类默认值,API端检测到就会直接拦截。 - 上传行为特征匹配异常:代码中配置
chunksize=-1,即整个视频文件单块一次性上传,和普通用户网页端分片上传的行为特征不符;如果同时存在短时间内频繁上传、使用机房IP/代理IP上传的情况,会被判定为自动化脚本批量发布垃圾内容,直接触发违规标记。 - 风控流程差异:API上传没有网页端的前置校验引导环节,只要命中风控规则就直接将视频锁为私密,不会像网页端那样提前提示可能存在问题的内容模块、给用户调整修正的机会。
涉及的Python代码
#!/usr/bin/python import http.client import httplib2 import os import random import sys import time from googleapiclient.discovery import build from googleapiclient.errors import HttpError from googleapiclient.http import MediaFileUpload from oauth2client.client import flow_from_clientsecrets from oauth2client.file import Storage from oauth2client.tools import argparser, run_flow # 显式配置底层HTTP传输库不自动重试,重试逻辑由代码自行实现 httplib2.RETRIES = 1 # 上传失败最大重试次数 MAX_RETRIES = 10 # 触发重试的异常类型 RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, http.client.NotConnected, http.client.IncompleteRead, http.client.ImproperConnectionState, http.client.CannotSendRequest, http.client.CannotSendHeader, http.client.ResponseNotReady, http.client.BadStatusLine) # 触发重试的HTTP状态码 RETRIABLE_STATUS_CODES = [500, 502, 503, 504] # 存储OAuth2.0凭证的文件名,需从Google API控制台获取,且要为对应项目启用YouTube Data API CLIENT_SECRETS_FILE = "client_secret_web.json" # 视频上传权限范围 YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload" YOUTUBE_API_SERVICE_NAME = "youtube" YOUTUBE_API_VERSION = "v3" # 凭证文件缺失时的提示信息 MISSING_CLIENT_SECRETS_MESSAGE = """ WARNING: Please configure OAuth 2.0 To make this sample run you will need to populate the client_secrets.json file found at: %s with information from the API Console """ % os.path.abspath(os.path.join(os.path.dirname(__file__), CLIENT_SECRETS_FILE)) VALID_PRIVACY_STATUSES = ("public", "private", "unlisted") def get_authenticated_service(args): flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_UPLOAD_SCOPE, message=MISSING_CLIENT_SECRETS_MESSAGE) storage = Storage("%s-oauth2.json" % sys.argv[0]) credentials = storage.get() if credentials is None or credentials.invalid: credentials = run_flow(flow, storage, args) return build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, http=credentials.authorize(httplib2.Http())) def initialize_upload(youtube, options): tags = None if options.keywords: tags = options.keywords.split(",") body=dict( snippet=dict( title=options.title, description=options.description, tags=tags, categoryId=options.category ), status=dict( privacyStatus=options.privacyStatus ) ) # 调用videos.insert接口创建并上传视频 insert_request = youtube.videos().insert( part=",".join(body.keys()), body=body, media_body=MediaFileUpload(options.file, chunksize=-1, resumable=True) ) resumable_upload(insert_request) # 指数退避策略实现断点续传/失败重试 def resumable_upload(insert_request): response = None error = None retry = 0 while response is None: try: print("Uploading file...") status, response = insert_request.next_chunk() if response is not None: if 'id' in response: print("Video id '%s' was successfully uploaded." % response['id']) else: exit("The upload failed with an unexpected response: %s" % response) except HttpError as e: if e.resp.status in RETRIABLE_STATUS_CODES: error = "A retriable HTTP error %d occurred:\n%s" % (e.resp.status, e.content) else: raise except RETRIABLE_EXCEPTIONS as e: error = "A retriable error occurred: %s" % e if error is not None: print(error) retry += 1 if retry > MAX_RETRIES: exit("No longer attempting to retry.") max_sleep = 2 ** retry sleep_seconds = random.random() * max_sleep print("Sleeping %f seconds and then retrying..." % sleep_seconds) time.sleep(sleep_seconds) if __name__ == '__main__': argparser.add_argument("--file", required=True, help="Video file to upload") argparser.add_argument("--title", help="Video title", default="Test Title") argparser.add_argument("--description", help="Video description", default="Test Description") argparser.add_argument("--category", default="22", help="Numeric video category. ") argparser.add_argument("--keywords", help="Video keywords, comma separated", default="") argparser.add_argument("--privacyStatus", choices=VALID_PRIVACY_STATUSES, default=VALID_PRIVACY_STATUSES[0], help="Video privacy status.") args = argparser.parse_args() if not os.path.exists(args.file): exit("Please specify a valid file using the --file= parameter.") youtube = get_authenticated_service(args) try: initialize_upload(youtube, args) except HttpError as e: print("An HTTP error %d occurred:\n%s" % (e.resp.status, e.content))
平台返回错误
视频因违反垃圾内容、欺骗性行为及诈骗相关政策,已被自动设置为私密状态。
内容的提问来源于stack exchange,提问作者raman singh
相关产品推荐
相关产品推荐

