【问题标题】:Youtube Data API V3 returning ssl.SSLWantWriteError: The operation did not complete (write) errorYoutube Data API V3 返回 ssl.SSLWantWriteError: The operation did not complete (write) 错误
【发布时间】:2020-12-21 22:28:32
【问题描述】:

我之前问过几乎相同的问题,但由于在尝试解决该问题时出现了一个新错误,这使最初的错误黯然失色,因此未能得到解决方案。问题是,当我尝试使用下面的代码上传 youtube 视频时,标题中出现错误(下面的完整跟踪)并且无法这样做。我对导致错误的原因一无所知,希望能提供任何帮助。

def upload(beatName, mainArtist, keywords, oneLiner):

    CLIENT_SECRET_FILE = 'client_secret.json'
    API_NAME = 'youtube'
    API_VERSION = 'v3'
    SCOPES = ['https://www.googleapis.com/auth/youtube']

    service = Create_Service(CLIENT_SECRET_FILE, API_NAME, API_VERSION, SCOPES)

    upload_date_time = DT.datetime(2020, 9, 3, 12, 30, 0).isoformat() + '.000Z'

    title = "OTOROSHI - "test"
    description = 'Test'

    request_body = {
        'snippet': {
            'categoryI': 10,
            'title': title,
            'description': description,
            'tags': keywords
        },
        'status': {
            'privacyStatus': 'private',
            'publishAt': upload_date_time,
            'selfDeclaredMadeForKids': False,
        },
        'notifySubscribers': True
    }

    mediaFile = MediaFileUpload('E:\Everything.mp4')

    response_upload = service.videos().insert(
        part = 'snippet,status',
        body = request_body,
        media_body = mediaFile
    ).execute()
client_secret.json-youtube-v3-(['https://www.googleapis.com/auth/youtube'],)
['https://www.googleapis.com/auth/youtube']
youtube service created successfully
[INFO   ] [Base        ] Leaving application in progress...
 Traceback (most recent call last):
   File "C:/Users/ricsi/Desktop/Automatic Uploader/main.py", line 34, in <module>
     AutomaticUploader().run()
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\app.py", line 950, in run
     runTouchApp()
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\base.py", line 573, in runTouchApp
     EventLoop.mainloop()
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\base.py", line 347, in mainloop
     self.idle()
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\base.py", line 391, in idle
     self.dispatch_input()
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\base.py", line 342, in dispatch_input
     post_dispatch_input(*pop(0))
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\base.py", line 248, in post_dispatch_input
     listener.dispatch('on_motion', etype, me)
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\core\window\__init__.py", line 1412, in on_motion
     self.dispatch('on_touch_down', me)
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\core\window\__init__.py", line 1428, in on_touch_down
     if w.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
     if child.dispatch('on_touch_down', touch):
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\uix\behaviors\button.py", line 151, in on_touch_down
     self.dispatch('on_press')
   File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
   File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1132, in kivy._event.EventObservers._dispatch
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\kivy\lang\builder.py", line 57, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "C:\Users\ricsi\Desktop\Automatic Uploader\automaticuploader.kv", line 53, in <module>
     on_press: root.upload()
   File "C:/Users/ricsi/Desktop/Automatic Uploader/main.py", line 27, in upload
     upload(beatName, mainArtist, keywords, oneLiner)
   File "C:\Users\ricsi\Desktop\Automatic Uploader\youtube.py", line 228, in upload
     response_upload = service.videos().insert(
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\googleapiclient\_helpers.py", line 134, in positional_wrapper
     return wrapped(*args, **kwargs)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\googleapiclient\http.py", line 892, in execute
     resp, content = _retry_request(
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\googleapiclient\http.py", line 204, in _retry_request
     raise exception
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\googleapiclient\http.py", line 177, in _retry_request
     resp, content = http.request(uri, method, *args, **kwargs)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\google_auth_httplib2.py", line 200, in request
     response, content = self.http.request(
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\httplib2\__init__.py", line 1985, in request
     (response, content) = self._request(
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\httplib2\__init__.py", line 1650, in _request
     (response, content) = self._conn_request(
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\site-packages\httplib2\__init__.py", line 1558, in _conn_request
     conn.request(method, request_uri, body, headers)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\http\client.py", line 1255, in request
     self._send_request(method, url, body, headers, encode_chunked)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\http\client.py", line 1301, in _send_request
     self.endheaders(body, encode_chunked=encode_chunked)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\http\client.py", line 1250, in endheaders
     self._send_output(message_body, encode_chunked=encode_chunked)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\http\client.py", line 1049, in _send_output
     self.send(chunk)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\http\client.py", line 971, in send
     self.sock.sendall(data)
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\ssl.py", line 1204, in sendall
     v = self.send(byte_view[count:])
   File "C:\Users\ricsi\Anaconda3\envs\Automatic Uploader\lib\ssl.py", line 1173, in send
     return self._sslobj.write(data)
 ssl.SSLWantWriteError: The operation did not complete (write) (_ssl.c:2472)

Process finished with exit code 1

【问题讨论】:

  • 从您的计算机命令行针对标准 Python3 解释器运行您的脚本是否成功?
  • @stvar 不,同样的错误仍然存​​在..
  • 但据我所知,它在几天前就起作用了,对吧?
  • 没有。我只是设法通过了身份验证过程。自原始帖子以来,它自己的上传一直没有奏效。当我重新测试它并制定一个很好的答案时,我实际上并没有成功上传视频,因为我发布了最后一个问题。 @stvar
  • 好的,再次感谢您抽出宝贵时间@stvar!我会尝试使用 oauth 操场并让您更新!

标签: python pycharm youtube-data-api


【解决方案1】:

概要

TLS/SSL 错误是由于以下任一级别可能发生的问题引起的:

  1. 客户端应用程序的级别;
  2. Google API 客户端库的级别及其相应的要求(请参阅下面列出的);
  3. 标准 Python 的 SSL 实现级别 (TLS/SSL wrapper for socket objects);
  4. 操作系统本身的级别。

针对上述OP的问题,我的建议如下:

客户端应用程序级别处理 SSL 错误,如果遇到上述错误,不要一次性上传视频文件,请使用@ 987654322@.

对于 Python v2 和 v3,YouTube 数据 API 的可恢复上传功能的使用非常容易,如下所示。

请注意,使用此功能将使应用对网络相关错误更具弹性

详情

在尝试使用下面引用的 Python 脚本之前,应确保下面列出的所有库(即 Python 包)都是最新的。 (只需在每个命名包上发出pip install --upgrade。)

在修改您的应用之前,请测试 API 的可恢复上传功能(即Resumable Uploading Protocol)确实可以正常工作且不会出现错误(因此也不会出现 SSL 错误)。

首先要做的是下载久经考验的公共 Google 脚本upload_video.py。 (这个脚本也有一个official documentation。要从脚本中获得一个不言自明的使用信息页面,只需使用命令行选项--help发出它。)

如果您运行的是 Python v3,那么您必须修补 upload_video.py,如下所示。在任何情况下,为了测试可恢复上传功能,只需在命令行提示符下发出如下命令:

python upload_video.py --file your_video_file.mp4 --title '...' --description '...' --privacyStatus private

或者,根据情况:

python3 upload_video.py --file your_video_file.mp4 --title '...' --description '...' --privacyStatus private

请注意,您的客户端机密文件 -- client_secret.json -- 必须存在于托管 upload_video.py 的目录中。

upload_video.py 成功运行后,请在您自己的 YouTube Studio 页面上检查新上传的视频(并最终将其删除):

https://studio.youtube.com/channel/YOUR_CHANNEL_ID/videos/upload.

如果一切正常——没有 SSL 错误——那么您可以继续重构自己的代码,以便根据您的需要将 Python 代码包含在 upload_video.py 中。

修补upload_video.py

目前由 Google 提供,脚本 upload_video.py 使用 Python v2 语言编码;要使其与 Python v3 一起使用,请对其应用以下更改:

  1. 此脚本的第一行:将 python 替换为 python3(这在 Windows 机器上不是必需的);
  2. import httplib 替换为import http.client
  3. 将所有出现的httplib. 替换为http.client.(请注意那里的点);
  4. 将所有print EXPRESSION 替换为print(EXPRESSION)
  5. 将所有except IDENTIFIER, e 替换为except IDENTIFIER as e

或者,否则,请将以下.patch 文件应用于脚本文件:

--- upload_video.py
+++ upload_video.py
@@ -1,7 +1,7 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import argparse
-import httplib
+import http.client
 import httplib2
 import os
 import random
@@ -23,10 +23,10 @@
 MAX_RETRIES = 10
 
 # Always retry when these exceptions are raised.
-RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, httplib.NotConnected,
-  httplib.IncompleteRead, httplib.ImproperConnectionState,
-  httplib.CannotSendRequest, httplib.CannotSendHeader,
-  httplib.ResponseNotReady, httplib.BadStatusLine)
+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)
 
 # Always retry when an apiclient.errors.HttpError with one of these status
 # codes is raised.
@@ -104,31 +104,31 @@
   retry = 0
   while response is None:
     try:
-      print 'Uploading file...'
+      print('Uploading file...')
       status, response = request.next_chunk()
       if response is not None:
         if 'id' in response:
-          print 'Video id "%s" was successfully uploaded.' % response['id']
+          print('Video id "%s" was successfully uploaded.' % response['id'])
         else:
           exit('The upload failed with an unexpected response: %s' % response)
-    except HttpError, e:
+    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, e:
+    except RETRIABLE_EXCEPTIONS as e:
       error = 'A retriable error occurred: %s' % e
 
     if error is not None:
-      print error
+      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
+      print('Sleeping %f seconds and then retrying...' % sleep_seconds)
       time.sleep(sleep_seconds)
 
 if __name__ == '__main__':
@@ -150,5 +150,5 @@
 
   try:
     initialize_upload(youtube, args)
-  except HttpError, e:
-    print 'An HTTP error %d occurred:\n%s' % (e.resp.status, e.content)
+  except HttpError as e:
+    print('An HTTP error %d occurred:\n%s' % (e.resp.status, e.content))

上面的.patch文件很可能是由Python自己的工具2to3生成的。该工具还能够就地修改upload_video.py。 (安装它只需发出pip install 2to3。)

【讨论】:

    猜你喜欢
    • 2020-12-16
    • 2022-07-30
    • 1970-01-01
    • 2013-06-14
    • 1970-01-01
    • 2019-11-14
    • 2018-05-15
    • 1970-01-01
    • 2022-12-05
    相关资源
    最近更新 更多