属性错误:“str”对象没有属性“write”,youtube-dl kivy

问题描述 投票:0回答:4

我目前正在开发一个小项目,需要 youtube-dl 在 kivy 环境中工作。我有 python 3.8.3、Kivy 1.11.1、youtube-dl 2020.5.8。除了这个问题之外,kivy 在 python3.8 上工作得很好。

我在尝试使用 youtube-dl 获取有关 YouTube 视频的信息时遇到此错误

AttributeError: 'str' object has no attribute 'write'

它确实适用于少数链接,但不适用于其他许多链接。

这个错误已经出现在 youtube-dl 的 github 页面 [[此处]][1] 上,但我找不到任何解决方案。

这是以下两个带有可重现示例的案例。

案例1

import youtube_dl from kivy.app import App from kivy.uix.button import Button class MusicApp(App): def build(self): return Button(text='Example') ydl_opts = { 'outtmpl': '%(title)s.%(ext)s', 'audio-format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], } with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download(['https://www.youtube.com/watch?v=BaW_jenozKc'])

输出

[INFO ] [Logger ] Record log in /home/adarsh/.kivy/logs/kivy_20-06-23_1.txt [INFO ] [Kivy ] v1.11.1 [INFO ] [Kivy ] Installed at "/usr/local/lib/python3.8/dist-packages/kivy/__init__.py" [INFO ] [Python ] v3.8.2 (default, Apr 27 2020, 15:53:34) [GCC 9.3.0] [INFO ] [Python ] Interpreter at "/usr/bin/python3" [INFO ] [Factory ] 184 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored) [INFO ] [Text ] Provider: sdl2(['text_pango'] ignored) [youtube] BaW_jenozKc: Downloading webpage [download] Resuming download at byte 215799 [download] Destination: youtube-dl test video ''_ä↭𝕐.f137.mp4 [download] 100% of 2.11MiB in 00:07.90KiB/s ETA 00:00 [download] Destination: youtube-dl test video ''_ä↭𝕐.f140.m4a [download] 100% of 154.06KiB in 00:00.07KiB/s ETA 00:00 [ffmpeg] Merging formats into "youtube-dl test video ''_ä↭𝕐.mp4" Deleting original file youtube-dl test video ''_ä↭𝕐.f137.mp4 (pass -k to keep) Deleting original file youtube-dl test video ''_ä↭𝕐.f140.m4a (pass -k to keep) [ffmpeg] Destination: youtube-dl test video ''_ä↭𝕐.mp3 Deleting original file youtube-dl test video ''_ä↭𝕐.mp4 (pass -k to keep)

案例2

import youtube_dl from kivy.app import App from kivy.uix.button import Button class MusicApp(App): def build(self): return Button(text='Example') ydl_opts = { 'outtmpl': '%(title)s.%(ext)s', 'audio-format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], } with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download(['https://www.youtube.com/watch?v=nTj4wVJAbNg'])

输出

[INFO ] [Logger ] Record log in /home/adarsh/.kivy/logs/kivy_20-06-23_2.txt [INFO ] [Kivy ] v1.11.1 [INFO ] [Kivy ] Installed at "/usr/local/lib/python3.8/dist-packages/kivy/__init__.py" [INFO ] [Python ] v3.8.2 (default, Apr 27 2020, 15:53:34) [GCC 9.3.0] [INFO ] [Python ] Interpreter at "/usr/bin/python3" [INFO ] [Factory ] 184 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored) [INFO ] [Text ] Provider: sdl2(['text_pango'] ignored) [youtube] nTj4wVJAbNg: Downloading webpage Traceback (most recent call last): File "temp/tmp.py", line 21, in <module> ydl.download(['https://www.youtube.com/watch?v=nTj4wVJAbNg']) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 2018, in download res = self.extract_info( File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 808, in extract_info return self.process_ie_result(ie_result, download, extra_info) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 863, in process_ie_result return self.process_video_result(ie_result, download=download) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 1644, in process_video_result self.process_info(new_info) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 1902, in process_info self.report_warning( File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 613, in report_warning self.to_stderr(warning_message) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 527, in to_stderr self._write_string(output, self._err_file) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/YoutubeDL.py", line 506, in _write_string write_string(s, out=out, encoding=self.params.get('encoding')) File "/home/adarsh/.local/lib/python3.8/site-packages/youtube_dl/utils.py", line 3174, in write_string out.buffer.write(byt) AttributeError: 'str' object has no attribute 'write'
即使有一些解决方法,也请提出建议。

编辑: 我将一个记录器传递给了 youtube-dl,该记录器取自他们的 github 页面

class MyLogger(object): def debug(self, msg): print("DEBUG " + msg) pass def warning(self, msg): print("WARNING " + msg) pass def error(self, msg): print("ERROR " + msg)
稍后我需要编写自己的记录器来获取下载进度。所以我将采用这个解决方案。
[1]:

https://github.com/ytdl-org/youtube-dl/issues/22109

python-3.x kivy youtube-dl
4个回答
2
投票
我正在做一个类似的项目并遇到了同样的错误。

我捕获了异常并打印了回溯

import traceback ... try: with youtube_dl.YoutubeDL(self.ydl_opts) as ydl: ydl.download([self.url]) except Exception as inst: print(inst) tb = traceback.format_exc() print(tb) pass
我得到了这个:

'str' object has no attribute 'write' Traceback (most recent call last): File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 797, in extract_info ie_result = ie.extract(url) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/extractor/common.py", line 530, in extract ie_result = self._real_extract(url) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/extractor/generic.py", line 2277, in _real_extract % (url, url), expected=True) youtube_dl.utils.ExtractorError: 'qsd' is not a valid URL. Set --default-search "ytsearch" (or run youtube-dl "ytsearch:qsd" ) to search YouTube During handling of the above exception, another exception occurred: Traceback (most recent call last): File "src/main.py", line 81, in run download_retcode = ydl.download([self.url]) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 2019, in download url, force_generic_extractor=self.params.get('force_generic_extractor', False)) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 820, in extract_info self.report_error(compat_str(e), e.format_traceback()) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 625, in report_error self.trouble(error_message, tb) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 578, in trouble self.to_stderr(message) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 527, in to_stderr self._write_string(output, self._err_file) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/YoutubeDL.py", line 506, in _write_string write_string(s, out=out, encoding=self.params.get('encoding')) File "/home/odrevet/.local/lib/python3.6/site-packages/youtube_dl/utils.py", line 3180, in write_string out.buffer.write(byt) AttributeError: 'str' object has no attribute 'write'
通过查看堆栈中的函数名称,我们可以看到当 ytdl 尝试报告另一个错误时发生错误(在本例中为:“youtube_dl.utils.ExtractorError:'qsd'不是有效的 URL”,因为我输入了我的程序中的“qsd”而不是有效的网址)。

通过查看 YoutubeDl.py 中的 to_stderr 函数,我们可以看到 out 应该是 sys.stderr,而在 utils.py 中出现错误的函数中:

def write_string(s, out=None, encoding=None): print(type(out)) # I added this line if out is None: out = sys.stderr assert type(s) == compat_str if sys.platform == 'win32' and encoding is None and hasattr(out, 'fileno'): if _windows_write_string(s, out): return if ('b' in getattr(out, 'mode', '') or sys.version_info[0] < 3): # Python 2 lies about mode of sys.stderr byt = s.encode(encoding or preferredencoding(), 'ignore') out.write(byt) elif hasattr(out, 'buffer'): enc = encoding or getattr(out, 'encoding', None) or preferredencoding() byt = s.encode(enc, 'ignore') out.buffer.write(byt) # Error on line 3180 else: out.write(s) out.flush()
stderr 根据 hasattr elif 检查有一个 buffer 属性,问题是 Kivy 如何处理错误流。根据我在 write_string 中添加的打印,stderr 被重新定义为 

,它确实有一个缓冲区属性,就像它应该是的 Stream 一样,但这个属性是一个简单的字符串。

参见

https://kivy.org/doc/stable/_modules/kivy/logger.html

class LogFile(object): def __init__(self, channel, func): self.buffer = '' # <-- a str self.func = func self.channel = channel self.errors = ''
我不知道是否可以参数 kivy 以使用 stderr 标准流,但我会检查。同时捕获异常并打印回溯,至少在“处理上述异常期间,发生了另一个异常”之前有原始错误

编辑:您可以将 stderr 重定向到文件

sys.stderr = open('./stderr', 'w')
    

0
投票
在 Android 上使用 youtube_dl 运行 kivy 应用程序来下载单个视频的音轨时,我遇到了同样的问题。下载相同的视频音频在 Windows 10 上运行正常。

我通过更改 youtube_dl 选项中的音频格式解决了该问题。这是代码摘录:

if os.name == 'posix': # on AndroidAndroid, FFmpegExtractAudio not available ! self.ydlOutTmplFormat = '/%(title)s.mp3' self.ydl_opts = { #'format': 'bestaudio/best', # for unknown reason, not working on # Android when used by AudioDownloaderGUI ! 'format': 'worstaudio/worst',# This fixes the error "AttributeError: # 'str' object has no attribute 'write'" 'quiet': YOUTUBE_DL_QUIET } else: self.ydlOutTmplFormat = '\\%(title)s.%(ext)s' self.ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '128', }], 'quiet': YOUTUBE_DL_QUIET }
我没有任何解释为什么这个修改可以解决问题。在不使用kivy的演示程序中使用Android上的youtube_dl时,不会出现该问题。这是我的演示代码:

import os, re import youtube_dl if os.name == 'posix': targetAudioDir = '/storage/emulated/0/Download/Audiobooks/test_youtube_dl' ydl_opts = { 'outtmpl': targetAudioDir + '/%(title)s.mp3', 'format': 'bestaudio/best', #'format': 'worstaudio/worst', 'quiet': False } else: targetAudioDir = 'D:\\Users\\Jean-Pierre\\Downloads\\Audiobooks\\test_youtube_dl' ydl_opts = { 'outtmpl': targetAudioDir + '\\%(title)s.%(ext)s', #'format': 'bestaudio/best', 'format': 'worstaudio/worst', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '96', }], 'quiet': False } singlevideoUrl = 'https://youtu.be/Eqy6M6qLWGw' with youtube_dl.YoutubeDL(ydl_opts) as ydl: # downloading single video meta = ydl.extract_info(singlevideoUrl, download=False) videoTitle = meta['title'] ydl.download([singlevideoUrl]) # not playable by kivy SoundLoader print('{} audio track downloaded'.format(videoTitle))
    

0
投票
我遇到了同样的问题,我使用

os

库解决了它。

  • 首先,我使用 YouTube.dl 函数创建一个

    convert.py

     脚本。

  • 其次,在 kivy 中,我没有调用 YouTube.dl,而是将链接保存在

    .txt

     文件中,然后使用带有要转换和准备的链接的 txt 来调用 
    os.system
     (
    python3 convert.py
    )。
    


0
投票

© www.soinside.com 2019 - 2024. All rights reserved.