如何将yt-dlp终端输出转为字典后生成Pandas DataFrame?
解决yt-dlp格式列表转Pandas DataFrame的问题
问题说明
想要通过URL获取视频格式列表,将yt-dlp的终端输出转为字典后生成Pandas DataFrame,但直接按行分割的方式未得到预期结果。
原尝试代码:
import subprocess import pandas as pd url = 'https://www.youtube.com/watch?v=kjYW63CVbsE' command = subprocess.getoutput('yt-dlp --list-formats "{url}"'.format(url=url)) output_lines = command.split('\n') headers = output_lines[6].split() format_list = [] for line in output_lines[::]: values = line.split() format_info = {} for i in range(len(headers)): format_info[headers[i]] = values[i] format_list.append(format_info) df = pd.DataFrame(format_list) print(df)
原代码的问题
- 字段拆分错误:直接用
split()会把带空格的字段(比如1080p 60fps)拆成多个元素,导致与表头的键值对应关系混乱。 - 未过滤无效行:yt-dlp输出包含开头说明文本、空行、分隔线等无格式数据的行,直接遍历所有行会引发键值不匹配甚至报错。
- 表头索引不可靠:依赖固定索引
output_lines[6]获取表头,不同环境或yt-dlp版本的输出行数可能变化,导致表头获取错误。
更可靠的两种解决方案
方案一:用yt-dlp的JSON输出直接解析(推荐)
yt-dlp支持直接输出JSON格式的结构化数据,无需手动解析终端文本,这是最稳定的方式:
import subprocess import json import pandas as pd url = 'https://www.youtube.com/watch?v=kjYW63CVbsE' # 调用yt-dlp,输出JSON格式的格式列表 result = subprocess.run( ['yt-dlp', '--list-formats', '--dump-json', url], capture_output=True, text=True, check=True ) # 解析每行JSON数据,得到格式条目列表 format_data = [json.loads(line) for line in result.stdout.strip().split('\n')] # 生成Pandas DataFrame df = pd.DataFrame(format_data) print(df)
说明:--dump-json参数让yt-dlp输出每个格式的JSON对象,每行一个,直接解析即可得到完整结构化数据,字段比终端输出更丰富。
方案二:改进终端输出的解析(适合必须用终端文本的场景)
如果一定要解析终端输出文本,需处理字段空格问题并过滤无效行:
import subprocess import pandas as pd import re url = 'https://www.youtube.com/watch?v=kjYW63CVbsE' command_output = subprocess.getoutput('yt-dlp --list-formats "{url}"'.format(url=url)) # 过滤空行并去除每行首尾空格 output_lines = [line.strip() for line in command_output.split('\n') if line.strip()] # 定位表头行(匹配包含"ID"和"RESOLUTION"的行) header_line = None for line in output_lines: if line.startswith('ID') and 'RESOLUTION' in line: header_line = line break if not header_line: raise ValueError("未找到格式列表表头") # 处理复合表头(比如"FRAME RATE"合并为"FRAME_RATE") headers = [] parts = header_line.split() i = 0 while i < len(parts): if parts[i] == 'FRAME' and i+1 < len(parts) and parts[i+1] == 'RATE': headers.append('FRAME_RATE') i += 2 else: headers.append(parts[i]) i += 1 # 跳过表头和分隔线,定位数据行起始位置 start_idx = output_lines.index(header_line) + 2 format_list = [] # 用正则匹配格式行,避免空格拆分问题 pattern = r'^(\d+)\s+(\w+)\s+(\S+\s*\S*)\s+(\d+\.?\d*)?\s+(\S+)\s+(\S+)\s*(.*)$' for line in output_lines[start_idx:]: match = re.match(pattern, line) if match: values = [v if v else None for v in match.groups()] format_info = dict(zip(headers[:len(values)], values)) format_list.append(format_info) df = pd.DataFrame(format_list) print(df)
说明:通过正则表达式匹配对齐的终端输出行,能有效处理带空格的字段,同时过滤无效数据行。
内容的提问来源于stack exchange,提问作者Gordon Chao
相关产品推荐
相关产品推荐

