You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Python批量下载音频时的SSL UNSAFE_LEGACY_RENEGOTIATION_DISABLED错误

解决SSL UNSAFE_LEGACY_RENEGOTIATION_DISABLED错误批量下载WAV文件

问题

从conllu文件中提取音频URL后,浏览器可正常下载WAV文件,但使用Python的urllib.request.urlretrieve批量下载时,出现以下错误:

URLError: <urlopen error [SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:1007)>

需处理300+音频文件,无法手动操作,寻求解决方案。

原代码

import os
import re
import urllib.request
from conll3 import *

import ssl
ssl._create_default_https_context = ssl._create_unverified_context


def extract_and_save_wav(file_path, output_directory):
    """
        Extracts and saves WAV audio file from a data file.

        Args:
             file_path (str): Path of the data file.
             output_directory (str): Output directory for the WAV audio file.

        Return:
             str or None: Path of the extracted and saved WAV audio file, or None if no audio file is found.
    """
    for root, dirs, files in os.walk(directory_path):
        for file in files:
            if file.endswith(".conllu"):
                file_path = os.path.join(root, file)
                trees = conllFile2trees(file_path)
                print(file_path)
                for tree in trees:
                    tree_str = str(tree)
                    sound_url_match = re.search(r'# sound_url = (.+)', tree_str)  # 查找音频文件URL
                    if sound_url_match:
                        sound_url = sound_url_match.group(1)
                        print(sound_url)
                        if sound_url.endswith('.wav'):
                            file_name = os.path.basename(file_path)
                            file_name_without_ext = os.path.splitext(file_name)[0]
                            output_file_name = f"{file_name_without_ext}.wav"
                            if output_directory is not None:
                                output_path = os.path.join(output_directory, output_file_name)
                                urllib.request.urlretrieve(sound_url, output_path)  # 下载并保存音频文件
                                return output_path
    return None


directory_path = "../SUD_Naija-NSC-master/non_gold/"
output_wav = "../WAV/non_gold/"

extract_and_save_wav(directory_path, output_wav)

错误信息

Reloaded modules: conll3
../SUD_Naija-NSC-master/non_gold/LAG_01_Hairdressing_M.conllu
http://naijasyncor.huma-num.fr/carte/mp3/LAG_01_Hairdressing_M.wav
Traceback (most recent call last):

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:1348 in do_open
    h.request(req.get_method(), req.selector, req.data, headers,

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:1283 in request
    self._send_request(method, url, body, headers, encode_chunked)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:1329 in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:1278 in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:1038 in _send_output
    self.send(msg)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:976 in send
    self.connect()

  File ~/miniconda3/envs/tal-ml/lib/python3.10/http/client.py:1455 in connect
    self.sock = self._context.wrap_socket(self.sock,

  File ~/miniconda3/envs/tal-ml/lib/python3.10/ssl.py:513 in wrap_socket
    return self.sslsocket_class._create(

  File ~/miniconda3/envs/tal-ml/lib/python3.10/ssl.py:1071 in _create
    self.do_handshake()

  File ~/miniconda3/envs/tal-ml/lib/python3.10/ssl.py:1342 in do_handshake
    self._sslobj.do_handshake()

SSLError: [SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:1007)


During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File ~/miniconda3/envs/tal-ml/lib/python3.10/site-packages/spyder_kernels/py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File ~/Desktop/Stage 2023-2024/Python/recuperation_audio.py:47
    extract_and_save_wav(directory_path, output_wav)

  File ~/Desktop/Stage 2023-2024/Python/recuperation_audio.py:39 in extract_and_save_wav
    urllib.request.urlretrieve(sound_url, output_path)  # 下载并保存音频文件

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:241 in urlretrieve
    with contextlib.closing(urlopen(url, data)) as fp:

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:216 in urlopen
    return opener.open(url, data, timeout)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:525 in open
    response = meth(req, response)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:634 in http_response
    response = self.parent.error(

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:557 in error
    result = self._call_chain(*args)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:496 in _call_chain
    result = func(*args)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:749 in http_error_302
    return self.parent.open(new, timeout=req.timeout)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:519 in open
    response = self._open(req, data)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:536 in _open
    result = self._call_chain(self.handle_open, protocol, protocol +

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:496 in _call_chain
    result = func(*args)

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:1391 in https_open
    return self.do_open(http.client.HTTPSConnection, req,

  File ~/miniconda3/envs/tal-ml/lib/python3.10/urllib/request.py:1351 in do_open
    raise URLError(err)

URLError: <urlopen error [SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:1007)>

解决方案

问题原因

服务器使用了旧版SSL重协商协议,Python 3.10+默认禁用了这种不安全的协商方式,导致握手失败。另外原代码存在参数错误:函数extract_and_save_wav定义的参数是file_path,但函数内部使用未定义的directory_path,会触发NameError。

修正步骤

  1. 修复函数参数错误:将函数参数改为directory_path,匹配内部使用的变量
  2. 创建兼容旧版SSL的上下文:使用ssl.SSLContext并启用OP_LEGACY_SERVER_CONNECT选项(Python 3.10+支持),允许与旧版服务器进行SSL协商
  3. 使用自定义上下文下载:创建自定义opener并安装,让urlretrieve使用该上下文
  4. 增强鲁棒性:添加目录自动创建、重复文件检查和错误捕获

完整修正代码

import os
import re
import urllib.request
from conll3 import *
import ssl


def extract_and_save_wav(directory_path, output_directory):
    """
        Extracts and saves WAV audio file from a data file.

        Args:
             directory_path (str): Path of the directory containing data files.
             output_directory (str): Output directory for the WAV audio file.

        Return:
             list: List of saved WAV file paths, or empty list if no files found.
    """
    # 创建支持旧版SSL重协商的上下文
    ctx = ssl.create_default_context()
    ctx.options |= ssl.OP_LEGACY_SERVER_CONNECT
    # 安装自定义opener
    opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))
    urllib.request.install_opener(opener)

    saved_paths = []
    # 确保输出目录存在
    os.makedirs(output_directory, exist_ok=True)

    for root, dirs, files in os.walk(directory_path):
        for file in files:
            if file.endswith(".conllu"):
                file_path = os.path.join(root, file)
                trees = conllFile2trees(file_path)
                print(f"Processing: {file_path}")
                for tree in trees:
                    tree_str = str(tree)
                    sound_url_match = re.search(r'# sound_url = (.+)', tree_str)
                    if sound_url_match:
                        sound_url = sound_url_match.group(1).strip()
                        print(f"Found URL: {sound_url}")
                        if sound_url.endswith('.wav'):
                            file_name = os.path.basename(file_path)
                            file_name_without_ext = os.path.splitext(file_name)[0]
                            output_file_name = f"{file_name_without_ext}.wav"
                            output_path = os.path.join(output_directory, output_file_name)
                            # 避免重复下载
                            if not os.path.exists(output_path):
                                try:
                                    urllib.request.urlretrieve(sound_url, output_path)
                                    saved_paths.append(output_path)
                                    print(f"Saved to: {output_path}")
                                except Exception as e:
                                    print(f"Failed to download {sound_url}: {str(e)}")
                            else:
                                print(f"File already exists: {output_path}")
    return saved_paths


directory_path = "../SUD_Naija-NSC-master/non_gold/"
output_wav = "../WAV/non_gold/"

saved_files = extract_and_save_wav(directory_path, output_wav)
print(f"\nTotal saved files: {len(saved_files)}")

内容的提问来源于stack exchange,提问作者Peilin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:54:54