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

使用PyScript开发YouTube下载器时遭遇URLError问题求助

PyScript 结合 Pytube 出现 URLError 的解决方法

问题重现

使用PyScript开发YouTube下载器时,运行代码触发URLError:

<py-env>
    - pytube
</py-env>

<py-script>
    from pytube import YouTube
    url="https://www.youtube.com/watch?v=7BXJIjfJCsA&t=111s"
    my_video=YouTube(url)
    print(my_video.title)
</py-script>

报错信息:

JsException(PythonError: Traceback (most recent call last): 
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 429, 
in eval_code .run(globals, locals) 
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 300, 
in run coroutine = eval(self.code, globals, locals) 
File "", line 4, 
in 
File "/lib/python3.10/site-packages/pytube/__main__.py", line 341, 
in title self._title = self.vid_info['videoDetails']['title'] 
File "/lib/python3.10/site-packages/pytube/__main__.py", line 246, 
in vid_info innertube_response = innertube.player(self.video_id) 
File "/lib/python3.10/site-packages/pytube/innertube.py", line 300, 
in player return self._call_api(endpoint, query, self.base_data) 
File "/lib/python3.10/site-packages/pytube/innertube.py", line 242, 
in _call_api response = request._execute_request( 
File "/lib/python3.10/site-packages/pytube/request.py", line 37, 
in _execute_request return urlopen(request, timeout=timeout) # nosec 
File "/lib/python3.10/urllib/request.py", line 216, 
in urlopen return opener.open(url, data, timeout) 
File "/lib/python3.10/urllib/request.py", line 519, 
in open response = self._open(req, data) 
File "/lib/python3.10/urllib/request.py", line 541, 
in _open return self._call_chain(self.handle_open, 'unknown', 
File "/lib/python3.10/urllib/request.py", line 496, 
in _call_chain result = func(*args) 
File "/lib/python3.10/urllib/request.py", line 1419, 
in unknown_open raise URLError('unknown url type: %s' % type) urllib.error.URLError:

问题原因

  1. 浏览器跨域限制:PyScript运行在浏览器环境中,受同源策略约束,pytube自带的urllib直接请求YouTube接口会被浏览器拦截。
  2. Pyodide环境兼容性:Pyodide(PyScript的底层运行环境)的urllib实现与本地Python存在差异,无法正确处理pytube生成的部分请求URL。

解决方法

方法一:替换pytube的请求逻辑为浏览器Fetch API

通过覆盖pytube的请求方法,使用浏览器原生的Fetch API替代urllib,避开跨域和环境兼容问题:

<py-env>
    - pytube==15.0.0
</py-env>

<py-script>
    from pytube import YouTube
    from js import fetch
    import urllib.request
    import pytube.request

    async def custom_execute_request(url, method='GET', headers=None, data=None, timeout=10):
        headers = headers or {}
        req_options = {
            'method': method,
            'headers': headers
        }
        if data:
            req_options['body'] = data
        
        response = await fetch(url, **req_options)
        if not response.ok:
            raise urllib.error.URLError(f"HTTP error: {response.status} {response.statusText}")
        return await response.text()

    # 替换pytube的请求方法
    pytube.request._execute_request = custom_execute_request

    # 简化URL,去掉多余参数测试
    url = "https://www.youtube.com/watch?v=7BXJIjfJCsA"
    # 异步执行需要用async/await
    async def get_video_info():
        my_video = YouTube(url)
        print(my_video.title)
    
    await get_video_info()
</py-script>

方法二:使用后端代理转发请求

如果上述方法仍有问题,可搭建一个简单的后端服务(如Flask),由后端调用pytube处理请求,PyScript通过调用后端接口获取数据:

  1. 后端示例(Flask):
from flask import Flask, request, jsonify
from pytube import YouTube
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route('/get-video-title', methods=['GET'])
def get_video_title():
    video_id = request.args.get('id')
    if not video_id:
        return jsonify({'error': 'Missing video ID'}), 400
    try:
        yt = YouTube(f"https://www.youtube.com/watch?v={video_id}")
        return jsonify({'title': yt.title})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True)
  1. PyScript调用后端接口:
<py-script>
    from js import fetch

    async def get_title():
        video_id = "7BXJIjfJCsA"
        response = await fetch(f"http://localhost:5000/get-video-title?id={video_id}")
        data = await response.json()
        if 'title' in data:
            print(data['title'])
        else:
            print(f"Error: {data['error']}")
    
    await get_title()
</py-script>

方法三:简化URL参数

尝试去掉URL中的多余参数(如&t=111s),仅保留基础的视频ID部分,部分情况下可避免URL解析异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:18:26