
简介面向视频批量制作与自动化剪辑场景一款Python实现的小工具基于剪映项目文件采用JSON存储的机制通过生成draft_content.json、draft_meta_info.json等草稿结构快速创建剪映轨道并自动生成视频草稿。资源共13个文件以9个Python脚本为核心覆盖草稿对象、素材管理、轨道操作、模板加载及主程序入口等模块另有2个JSON模板、1份Markdown说明文档和.gitignore压缩包仅11KB轻量易部署。目前已有1982人学习下载适合具备一定Python基础、希望简化剪映草稿创建流程的创作者、视频自媒体或自动化运维人员。脚本实现了“草稿媒体库→内容媒体库→轨道片段”的完整添加链路add_media_to_track可自动识别音频、视频类型并加入对应轨道无视频轨道时还会先创建视频轨道用户只需在main.py中指定本地媒体路径即可将音乐与视频一键转为可编辑的剪映草稿省去手动拖拽编排的重复操作同时保留模板目录便于二次扩展。 先交代一下背景。我当时接到一个很具体的需求每周要交付几十条不同文案、不同素材的混剪短视频。如果每一条都在剪映里手动拖素材、排轨道、加字幕一天也就做十几条而且机械操作特别容易出错。后来我开始研究剪映草稿的文件格式发现剪映草稿本身就是一套 JSON 数据轨道、素材、字幕、音频全部是结构化的字段。于是就有了用 Python 直接写草稿轨道的想法也就是 JianYingProDraft 这类项目的核心思路不打开剪映直接生成可以识别、可以继续编辑的剪映草稿文件然后让剪映自动渲染出成片。这篇文章会把整个方案拆开讲为什么这条路可行、环境怎么搭、核心代码怎么写、常见坑怎么避以及怎么把它扩展成真正的批量生产工具。内容面向有一定 Python 基础、不了解剪映草稿结构的朋友如果你完全没写过 Python前半部分看完也能知道值不值得学后半部分可以直接抄代码。1. 为什么剪映草稿能被 Python 接管结构里的秘密1.1 剪映草稿不止是软件工程更是一套公开的 JSON 协议很多人以为剪映草稿是某种加密的私有格式实际上当你用剪映保存一个草稿后在草稿目录下会看到两个关键文件draft_content.json和draft_meta_info.json。前者存的是用户真正编辑的内容——素材列表、轨道、转场、字幕、贴纸、音频、画布参数全在这里后者存的是草稿的元信息比如缩略图、最近编辑时间、界面面板状态。我最早是抱着“试一试”的心态打开这个 JSON 的结果发现结构相当清晰。顶层有几个大块canvas_config控制画布分辨率、帧率、背景色materials存放所有导入的素材包括视频、图片、音频、文本、贴纸、转场tracks则是时间线上的轨道数组每个轨道又包含segments每个 segment 指向一个material_id并声明自己在时间轴上的target_timerange。只要把这两个关键值理解透就等于掌握了剪映草稿的骨架。draft_content.json本质上是一个树形状态描述文件剪映打开草稿时做的事情就是把这个 JSON 反序列化然后把每个节点渲染成时间线上的轨道块。反过来说只要我们能生成一个符合剪映解析规则、字段完整、UUID 不冲突的 JSON剪映就会把它当作正常草稿来打开。这就是整个自动化方案的根基。1.2 为什么选 Python而不是直接改 JSON有人会问JSON 是纯文本直接用文本编辑器手写不就行了瓶颈在于两点第一素材多了之后JSON 动辄几万行手写几乎不可能维护第二我们需要的不是“改一条草稿”而是“批量生成几十条结构和逻辑各不相同、但模板统一的草稿”这本质上是程序化的事情。Python 在这个场景的优势非常明显。它本身就是处理文本和数据的利器标准库里的json、uuid、os、re基本够用再加上脚本可以写循环、写配置、接字幕文件、接音频文件名一套代码跑下来就能批量产出草稿。相比用剪映的“草稿另存为”再手工替换Python 方案快捷且可复现改一个文案只需要重新跑一次脚本。另一个实际原因是剪映草稿素材的路径、字幕内容、声音文件都存在同一个 JSON 里Python 处理这些字符串特别顺手。比如从 Excel 读一批商品名自动生成对应字幕文件和配音文件再把它们组合进草稿整个过程不需要打开剪映也能基本完成只在最后渲染成片时才打开剪映。这也是我认同这类工具的最重要理由它把“剪辑”从手工劳动变成了“数据处理渲染”两步。2. 准备环境装 Python、建工程、先解剖一个真实草稿2.1 Python 环境安装与项目依赖我用的是 Python 3.8实际上 3.6 以上都可以跑。Windows 用户直接去 python.org 下载安装包安装时记得勾选 “Add Python to PATH”否则后面在命令行敲python会提示找不到命令。macOS 用户建议用 Homebrew 装命令是brew install python3。这个项目不需要额外安装像 TensorFlow 那样的重型依赖标准库就够了。实操时只需确保 Python 能用import json、import uuid、import os这三个库。一个空目录、一个.py文件就是整个项目的基础工程。我的目录结构是jianying_draft_generator/ ├── generate_draft.py # 主脚本负责拼装 JSON ├── templates/ # 模板 JSON从剪映导出的草稿提取 ├── assets/ # 图片、视频、音频素材 └── output/ # 生成的草稿目录如果已经安装了剪映并且有一个手动建好的空白草稿强烈建议先把这个草稿的draft_content.json复制一份到templates/里。它就是你最好的“字段参考手册”比任何网上的文档都准。2.2 解剖样例从模板草稿里找到必填字段我当年踩的第一个坑就是“自作聪明”地按网上看到的字段写了一版结果剪映直接报“草稿打开失败”。后来学乖了先用剪映随便建一个项目放一张图、一段文本然后导出草稿目录把draft_content.json拿到代码编辑器里逐层展开对照着写。这里说的必填字段有几个关键位置canvas_config.ratio画布比例比如16:9、9:16同时还有width和height。实测如果不匹配素材会被拉伸或裁剪。materials下的videos、images、audios、texts每个素材对象都带一个全局唯一的id剪映内部靠这个 id 引用素材不是靠素材路径。tracks数组轨道顺序代表层级最底下的主视频轨通常type为3文本轨一般为12音频轨一般带独立 type。其实不同剪映版本会对轨道类型做调整但 track 里的segments结构大体一致。看模板草稿时重点不是背字段而是理解“素材在 materials 里定义轨道在 tracks 里引用”这一层关系。只要这个引用关系不断剪映打开草稿基本就不会崩。简单说一下为什么不能用网上随意找的字段。剪映每个小版本的草稿结构都可能增减字段某次升级后我发现旧草稿仍能打开但新版本生成的草稿却打不开旧版剪映原因就出在版本兼容。所以最稳妥的办法导出你自己当前版本的草稿模板再围绕它做程序化填充。3. 核心代码从零生成一个可被剪映识别的草稿3.1 填充基础结构画布、材料容器、空轨道现在进入动手阶段。下面这段代码的目标是生成一个最简的draft_content.json剪映能打开并且跑完代码后我们可以继续往里面加素材和轨道。import json import uuid import os def new_id(): # 剪映中的素材 id 一般是没有横杠的大写 UUID return uuid.uuid4().hex.upper() class DraftBuilder: def __init__(self, ratio16:9, fps25, width1920, height1080): self.ratio ratio self.fps fps self.width width self.height height self.data self._init_base() def _init_base(self): draft { canvas_config: { ratio: self.ratio, width: self.width, height: self.height, fps: self.fps, background_color: #000000 }, materials: { videos: [], images: [], audios: [], texts: [], transitions: [], effects: [], stickers: [], amazons: [], vocal_separate_configs: [], text_codes: [] }, tracks: [] } return draft def save(self, output_dir): os.makedirs(output_dir, exist_okTrue) content_path os.path.join(output_dir, draft_content.json) meta_path os.path.join(output_dir, draft_meta_info.json) with open(content_path, w, encodingutf-8) as f: json.dump(self.data, f, ensure_asciiFalse, indent2) # draft_meta_info.json 是元信息本方案可先写入最简内容 meta { draft_fold_path: output_dir, edit_start_time: 0, last_modified_time: 0 } with open(meta_path, w, encodingutf-8) as f: json.dump(meta, f, ensure_asciiFalse, indent2) return content_path这段代码没有什么高深逻辑核心是先把“容器”建好。剪映打开草稿时如果materials缺少某些子列表可能导致黑屏或识别异常所以我们一开始就把所有常用容器全部初始化成空列表。canvas_config里的宽高和比例也要提前定好后面加素材时才好计算时长和坐标。3.2 添加图片素材和主视频轨道接下来是重头戏往材料列表里添加一张图片并且在主视频轨道上放入对应的 segment。这样剪映打开后就能在时间轴上看到一张静帧图。class DraftBuilder(DraftBuilder): def add_image_to_track(self, image_path, duration5, start0): # 1. 构造 image 素材 image_id new_id() image_material { id: image_id, path: image_path, duration: duration * 1_000_000, # 剪映内部时间单位是微秒 type: image, width: self.width, height: self.height } self.data[materials][images].append(image_material) # 2. 找到或创建主视频轨道type3 main_track None for track in self.data[tracks]: if track.get(type) 3: main_track track break if main_track is None: main_track { id: new_id(), type: 3, name: 主视频轨道, segments: [], is_default: True } self.data[tracks].append(main_track) # 3. 在轨道上追加 segment main_track[segments].append({ id: new_id(), material_id: image_id, target_timerange: { start: start * 1_000_000, duration: duration * 1_000_000 } })这里需要特别说明两个时间单位的细节。剪映草稿 JSON 里的时间单位是微秒不是秒。如果直接把 5 填进duration剪映会认为这个素材只持续 5 微秒时间轴上根本看不见。所以代码里统一用duration * 1_000_000做转换。这是很多初版脚本跑完打开草稿后“一片空白”的原因。另一个细节是“素材路径”。Windows 下剪映素材路径通常形如C:\Users\xxx\assets\1.jpg在 JSON 字符串里反斜杠会被转义。我建议代码里统一用正斜杠即image_path.replace(\\, /)这样保存出来的 JSON 可读性好剪映也能正确识别。实测剪映对正斜杠路径支持没问题省去很多转义烦恼。3.3 添加字幕文本内容与 time_range 要同步做混剪类视频字幕几乎是刚需。文本轨道和图片轨道的逻辑类似也是先建materials.texts素材再在轨道上放 segment。区别是文本素材需要带上具体的文字内容和字体属性。def add_text(self, content, start0, duration5, font_size12): text_id new_id() text_material { id: text_id, content: content, font_name: 默认字体, font_size: font_size, alignment: 1, color: #FFFFFF, duration: duration * 1_000_000 } self.data[materials][texts].append(text_material) text_track None for track in self.data[tracks]: if track.get(type) 12: text_track track break if text_track is None: text_track { id: new_id(), type: 12, name: 文本轨道, segments: [] } self.data[tracks].append(text_track) text_track[segments].append({ id: new_id(), material_id: text_id, target_timerange: { start: start * 1_000_000, duration: duration * 1_000_000 } })一些版本还会在文本 segment 下额外写入text_codes这是一个与歌词逐字时间轴相关的字段。如果只往content里写文字而不维护text_codes某些版本剪映可能会把字幕时间轴识别得不准确。稳妥做法是先在自己的模板草稿里添加一条字幕看导出的 JSON 里texts素材和轨道 segment 分别存了什么字段然后照着填充。不同版本差异较大唯有用你本机的模板去对齐才最可靠。字体颜色、字号这些值不一定每个版本都一模一样但content、start、duration这三个最核心的字段是通用的优先保证它们正确。3.4 保存草稿到剪映草稿目录脚本最后生成的是一个完整草稿目录目录名可以自己起。想让剪映客户端直接识别需要把整个目录放到剪映的草稿目录下通常是C:\Users\你的用户名\AppData\Local\JianyingPro\User Data\Projects\com.lveditor.draft。脚本里可以增加一步自动复制def install_draft(self, draft_name): # 先生成到当前目录 out self.save(draft_name) target_root os.path.expandvars( r%LOCALAPPDATA%\JianyingPro\User Data\Projects\com.lveditor.draft ) target_dir os.path.join(target_root, draft_name) os.makedirs(target_dir, exist_okTrue) content_path os.path.join(target_dir, draft_content.json) meta_path os.path.join(target_dir, draft_meta_info.json) shutil.copy2(out, content_path) # 把 meta 一起拷过去 meta_src os.path.join(draft_name, draft_meta_info.json) shutil.copy2(meta_src, meta_path) return target_dir%LOCALAPPDATA%是 Windows 环境变量展开后就是剪映草稿存储的根目录。如果剪映版本不同项目内的子目录名称可能有差异最笨也最有效的办法是手动存一个草稿然后在资源管理器里搜draft_content.json看它到底落在哪个绝对路径。后面脚本就指向那个路径。4. 实测踩坑剪映识别不了、黑屏、字幕不显示怎么办4.1 草稿文件打不开或提示损坏这是最常见的坑我刚开始写这工具时几乎每改一次结构就会遇到一次。原因大致有三类draft_content.json里缺少某个剪映版本必需的字段。一个新版剪映草稿里可能有materials.amazons、vocal_separate_configs等字段如果你从网上抄的旧模板没有新版剪映就会认为草稿损坏。UUID 重复或为空。个别偷懒代码用固定字符串“test”作为素材 id一旦同一条草稿里出现重复引用剪映会直接崩溃。JSON 格式本身不合法。比如多个对象之间漏了逗号或括号不匹配剪映解析失败后会给出“草稿打开失败”之类提示。排查思路很简单先在自己本机用剪映导出一个只含一张图片和一行字幕的草稿把它作为黄金模板然后代码生成结果和黄金模板做 diff字段差异在哪问题基本就在哪。我写了一个独立函数专门把两个 JSON 的顶层 key 集合对比打印出来几分钟就能定位。4.2 素材黑屏或显示“离线素材”黑屏一般不是轨道问题而是素材路径对不上。剪映打开草稿时发现materials里的某个素材路径不存在就会在时间轴显示“离线”。这种情况在批量移动素材目录后最容易出现。解决办法是确保生成草稿时素材路径和最终剪映打开草稿时素材所在位置一致。我一般在本地开发目录里用相对路径拼接最后批量执行前先做一次路径检查打开每个image_material[path]确认文件真实存在。如果素材是网络下载的先下载到本地再写草稿不要直接把 URL 写在路径里。4.3 字幕不显示或时间轴对不上字幕不显示的原因通常是文本素材里的字段不完整。有的剪映版本需要font_size大于 0并且alignment设成有效值有的则要求内容同时写在content和text_codes相关字段里。只改content不写text_codes在最严格的情况下会出现“字幕块在轨道上但播放预览时看不见文字”。如果发现时间轴对不上要检查target_timerange里的start和duration是否按微秒计算。举个例子我希望字幕从第 2 秒开始、持续 3 秒那么代码里必须填start2_000_000、duration3_000_000而不是 2 和 3。漏掉_000_000是最隐蔽的低级错误排查时优先怀疑这里。我把常见问题和排查思路整理成一张表方便对照现象优先排查点参考解法剪映提示草稿损坏JSON 缺失字段、UUID 重复、格式错误与本地模板草稿 diff补齐字段素材黑屏或离线素材路径不存在、存在中文路径转义问题统一正斜杠路径生成前检查文件存在字幕不显示文本素材缺字体/颜色字段或只写了 content对齐模板里的 texts 字段检查 text_codes时间轴错位数字没乘 1_000_000确认 target_timerange 使用微秒比例变形canvas_config 宽高比与素材不一致先固定画布比例再按比例准备素材5. 扩展玩法把脚本变成批量视频生产线5.1 用模板渲染代替手写 JSON当脚本能稳定生成一条草稿后下一个目标就是批量。批量生成不是把“加一张图、加一行字”循环十几次这么简单而是要先把“每条视频的差异点”抽出来比如图片路径、标题文字、背景音乐、字幕内容、时长。把这些差异点定义成一个列表然后遍历列表每遍历一次生成一个独立草稿。tasks [ { image: assets/product_01.jpg, title: 2025春季新品推荐, music: assets/bgm_01.mp3, duration: 8 }, { image: assets/product_02.jpg, title: 经典返场夏日限时优惠, music: assets/bgm_02.mp3, duration: 10 } ] for index, task in enumerate(tasks, 1): builder DraftBuilder(ratio9:16, width1080, height1920) builder.add_image_to_track(task[image], durationtask[duration]) builder.add_text(task[title], start0, durationtask[duration]) # 如果有配音或背景音乐再加 add_audio 方法 builder.save(foutput/draft_{index})这个循环里最核心的变化在于每轮循环都新建一个DraftBuilder防止上一轮数据污染下一轮。如果复用同一个对象素材、轨道会不断叠加最终草稿会包含前面所有素材的残余导出的成片完全不是你想要的。分而治之一次任务一个 builder是最稳妥的做法。5.2 与 TTS、Excel、素材命名规范打通批量生产的真正瓶颈其实不是 JSON 生成而是素材准备。如果 50 条视频对应 50 张图和 50 段音频手工准备素材仍然很累。我实践的路径是用 Excel 或 CSV 存放每条视频的标题、正文、音频文件名、图片文件名。脚本逐行读取 Excel用 Python 的openpyxl或标准库csv读数据。用 TTS 工具把文案批量转成音频输出文件名与 Excel 中记录的音频字段保持一致。图片按统一规范命名比如01.jpg、02.jpg脚本直接按序号拼接路径。这样真正需要人工介入的只有两步整理文案、检查最终成片。中间过程脚本自动完成。我见过有人把电商上品、详情页描述全部自动化接进来每天定时生成一批商品视频流程跑通了之后效率提升非常明显。建议还是先小规模验证先用脚本生成 3 条草稿手工打开剪映渲染 3 条成片确认没问题后再扩大到完整批次。否则一次性生成 50 条如果有一半因为路径问题打不开返工成本也不低。5.3 模板版本管理的小习惯最后分享一个我自己的习惯。因为剪映会隔段时间提示升级而升级后草稿 JSON 结构大概率会有细微变化我会在每次升级后做一次“模板快照”备份手动新建一个简单空白草稿把draft_content.json存成templates/template_vX.Y.Z.json。脚本里默认引用最新模板但如果换到旧机器或换到旧版剪映环境可以手动切换模板版本。这样做的价值在于脚本运行环境变化后你能快速确认是剪映版本变化导致的问题还是代码逻辑的问题。这比对着报错信息瞎猜高效得多。整个方案跑起来之后我的工作流就变成了准备文案 → 跑脚本生成草稿 → 打开剪映批量导出 → 抽检成片。剪映在这里回归到了它最擅长的“渲染器”角色而内容结构、轨道排布这些体力活全部交给了 Python。对这种用程序改造重复劳动的做法我也越来越深信先把数据结构搞清楚再想自动化绝大多数工具类需求都能找到类似突破口。本文还有配套的精品资源点击获取