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

从Bunny.NET拉取视频自动发布到Squarespace的Python脚本报错求助

批量同步Bunny.net视频到Squarespace的脚本错误排查与修复

问题背景

需要将数百个视频从Bunny.NET Stream同步到Squarespace,生成带预览和直接下载链接的竖屏视频网格,手动操作效率低,编写Python脚本后运行报错。

报错信息

Traceback (most recent call last):
  File "C:\Users\ervin\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\models.py", line 971, in json
    return complexjson.loads(self.text, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ervin\AppData\Local\Programs\Python\Python312\Lib\json\__init__.py", line 346, in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ervin\AppData\Local\Programs\Python\Python312\Lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ervin\AppData\Local\Programs\Python\Python312\Lib\json\decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\ervin\Desktop\publish_videos.py", line 60, in <module>
    main()
  File "C:\Users\ervin\Desktop\publish_videos.py", line 48, in main
    bunny_video_ids = fetch_all_video_ids(bunny_api_key)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ervin\Desktop\publish_videos.py", line 8, in fetch_all_video_ids
    return [video['id'] for video in response.json()['videos']]
                                     ^^^^^^^^^^^^^^^
  File "C:\Users\ervin\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\models.py", line 975, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

原脚本代码

import requests

# Function to fetch all video IDs from Bunny.net
def fetch_all_video_ids(api_key):
    url = 'https://api.bunny.net/videos'
    headers = {'AccessKey': api_key}
    response = requests.get(url, headers=headers)
    return [video['id'] for video in response.json()['videos']]

# Function to fetch video details from Bunny.net
def fetch_video_details(video_id, api_key):
    url = f'https://api.bunny.net/video/{video_id}/details'
    headers = {'AccessKey': api_key}
    response = requests.get(url, headers=headers)
    return response.json()

# Function to publish video grid on Squarespace
def publish_video_grid_on_squarespace(video_details_list, squarespace_api_key, page_id):
    # Creating HTML for video grid
    video_grid_html = '&lt;div class=&quot;video-grid&quot;&gt;'
    for video_details in video_details_list:
        video_url = video_details['url']
        download_url = video_details['downloadUrl']
        video_grid_html += f'&lt;div class=&quot;video-wrapper&quot;&gt;'
        video_grid_html += f'&lt;video src=&quot;{video_url}&quot; controls&gt;'
        video_grid_html += f'&lt;a href=&quot;{download_url}&quot; download&gt;Download Video&lt;/a&gt;&lt;/video&gt;'
        video_grid_html += '&lt;/div&gt;'
    video_grid_html += '&lt;/div&gt;'

    # Publishing video grid on Squarespace
    url = f'https://api.squarespace.com/1.0/{page_id}/collections'
    headers = {'Authorization': f'Bearer {squarespace_api_key}'}
    data = {
        'type': 'html',
        'html': video_grid_html
    }
    response = requests.post(url, headers=headers, json=data)
    return response.json()

# Main function
def main():
    # Set up your Bunny.net and Squarespace API credentials
    bunny_api_key = 'xxx'
    squarespace_api_key = 'xxx'
    squarespace_page_id = 'xxx'

    # Fetching all video IDs from Bunny.net
    bunny_video_ids = fetch_all_video_ids(bunny_api_key)

    # Fetching video details for each video and publishing video grid on Squarespace
    video_details_list = []
    for video_id in bunny_video_ids:
        video_details = fetch_video_details(video_id, bunny_api_key)
        video_details_list.append(video_details)

    response = publish_video_grid_on_squarespace(video_details_list, squarespace_api_key, squarespace_page_id)
    print(&quot;Video grid published on Squarespace:&quot;, response)

if __name__ == &quot;__main__&quot;:
    main()

错误原因与修复方案

1. Bunny.net API端点错误(核心问题)

原脚本使用的Bunny API URL不符合官方规范:

  • 视频列表API需要指定Library ID,正确端点为https://api.bunny.net/stream/{LIBRARY_ID}/videos
  • 视频详情API同样需要Library ID,正确端点为https://api.bunny.net/stream/{LIBRARY_ID}/video/{VIDEO_GUID}
  • 原URL返回非JSON内容(如404/403页面),导致JSON解析失败

2. 响应未做错误校验

未检查HTTP响应状态码,即使请求失败(如密钥无效、权限不足)仍尝试解析JSON,引发错误。

3. Squarespace API调用错误

原脚本使用的/collections端点不适合更新页面内容,正确的页面内容更新端点为https://api.squarespace.com/1.0/pages/{PAGE_ID},需用PUT请求而非POST。

4. HTML结构错误

<video>标签内不能嵌套<a>标签,需将下载链接移到video外部,保证HTML有效性。


修复后的脚本示例

import requests

def fetch_all_video_ids(api_key, library_id):
    url = f'https://api.bunny.net/stream/{library_id}/videos'
    headers = {'AccessKey': api_key}
    response = requests.get(url, headers=headers)
    response.raise_for_status()  # 自动抛出HTTP错误
    # Bunny返回的视频列表在items数组中,唯一标识为guid
    return [video['guid'] for video in response.json()['items']]

def fetch_video_details(video_guid, api_key, library_id):
    url = f'https://api.bunny.net/stream/{library_id}/video/{video_guid}'
    headers = {'AccessKey': api_key}
    response = requests.get(url, headers=headers)
    response.raise_for_status()
    video_data = response.json()
    # 整理所需字段:预览地址和下载地址
    return {
        'preview_url': video_data['playbackUrl'],
        'download_url': f"https://video.bunnycdn.com/{library_id}/{video_guid}/download.mp4"
    }

def publish_video_grid_on_squarespace(video_details_list, squarespace_api_key, page_id):
    # 修复HTML结构:下载链接放在video外部,添加基础样式
    video_grid_html = '<div class="video-grid" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px;">'
    for video in video_details_list:
        video_grid_html += f'''
        <div class="video-wrapper">
            <video src="{video['preview_url']}" controls style="width: 100%; height: auto;"></video>
            <a href="{video['download_url']}" download style="display: block; margin-top: 10px; text-align: center;">下载视频</a>
        </div>
        '''
    video_grid_html += '</div>'

    # 修正Squarespace API调用:更新页面内容
    url = f'https://api.squarespace.com/1.0/pages/{page_id}'
    headers = {
        'Authorization': f'Bearer {squarespace_api_key}',
        'Content-Type': 'application/json'
    }
    # 替换页面的HTML区块内容,实际需根据页面结构调整
    data = {
        'sections': [
            {
                'type': 'html',
                'html': video_grid_html
            }
        ]
    }
    response = requests.put(url, headers=headers, json=data)
    response.raise_for_status()
    return response.json()

def main():
    # 替换为实际的凭据
    bunny_api_key = 'YOUR_BUNNY_API_KEY'
    bunny_library_id = 'YOUR_BUNNY_LIBRARY_ID'
    squarespace_api_key = 'YOUR_SQUARESPACE_API_KEY'
    squarespace_page_id = 'YOUR_SQUARESPACE_PAGE_ID'

    try:
        bunny_video_guids = fetch_all_video_ids(bunny_api_key, bunny_library_id)
        video_details_list = []
        for guid in bunny_video_guids:
            details = fetch_video_details(guid, bunny_api_key, bunny_library_id)
            video_details_list.append(details)
        
        response = publish_video_grid_on_squarespace(video_details_list, squarespace_api_key, squarespace_page_id)
        print("视频网格已发布到Squarespace:", response)
    except Exception as e:
        print("执行出错:", str(e))

if __name__ == "__main__":
    main()

额外注意事项

  • 确保Bunny API密钥拥有对应Library的读取权限
  • Squarespace API需要开启权限,且页面ID需正确获取(可通过Squarespace开发者工具或API查询)
  • 若视频数量较多,建议添加分页逻辑(Bunny API默认返回20条,可通过page参数分页)
  • 可添加速率限制,避免触发API调用频率限制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:52:19