Python批量重命名影视文件实用技巧
时间:2025-07-22 09:36:37 213浏览 收藏
今日不肯埋头,明日何以抬头!每日一句努力自己的话哈哈~哈喽,今天我将给大家带来一篇《Python批量命名影视剧文件技巧》,主要内容是讲解等等,感兴趣的朋友可以收藏或者有更好的建议在评论提出,我都会认真看的!大家一起进步,一起学习!
用Python实现影视剧文件标准化命名的核心步骤是:遍历文件、解析旧名、构建新名、安全重命名;2. 解析依赖正则匹配剧集(SXXEXX/XXxYY)和电影(片名.年份)模式,并清理分辨率、组名等垃圾信息;3. 安全策略包括预览模式确认操作、跳过命名冲突避免覆盖、记录未解析文件便于手动处理,确保自动化过程可靠可控。
批量管理影视剧文件,尤其是在命名上,用Python来自动化这个过程简直是把繁琐变成了享受。它能帮助你把那些杂乱无章、下载时带着各种奇怪后缀和编码的文件,整理成一个统一、清晰、便于媒体服务器识别的格式。说白了,就是让你的数字媒体库告别“脏乱差”,变得井井有条。

解决方案
要用Python实现影视剧文件的标准化命名,核心思路就是:遍历文件、解析现有文件名、构建新文件名,最后执行重命名操作。这听起来简单,但实际操作中会遇到各种意想不到的“脏数据”,也就是那些不规范的文件名。所以,我们需要一套灵活的解析逻辑。
首先,我们需要一个函数来扫描指定目录下的所有文件。

import os import re import shutil def standardize_media_filenames(root_dir, preview_only=True): """ 标准化指定目录下影视剧文件的命名。 Args: root_dir (str): 要处理的根目录。 preview_only (bool): 如果为True,只打印将要进行的重命名操作,不实际执行。 """ print(f"开始扫描目录:{root_dir}") print("-" * 30) for dirpath, dirnames, filenames in os.walk(root_dir): for filename in filenames: # 过滤掉非媒体文件,可以根据需要扩展 if not any(filename.lower().endswith(ext) for ext in ['.mp4', '.mkv', '.avi', '.rmvb', '.flv', '.webm']): continue old_filepath = os.path.join(dirpath, filename) new_filename = parse_and_construct_new_name(filename) if new_filename and new_filename != filename: new_filepath = os.path.join(dirpath, new_filename) print(f"原文件: {filename}") print(f"新文件: {new_filename}") if not preview_only: try: # 检查目标文件是否已存在,避免覆盖 if os.path.exists(new_filepath): print(f"警告:目标文件已存在,跳过重命名:{new_filepath}") continue os.rename(old_filepath, new_filepath) print(f"成功重命名:{filename} -> {new_filename}") except OSError as e: print(f"错误:无法重命名 {filename} -> {new_filename}: {e}") print("-" * 30) elif new_filename == filename: print(f"文件 {filename} 已符合命名规范,跳过。") print("-" * 30) else: print(f"无法解析文件 {filename},跳过。") print("-" * 30) print("扫描完成。") if preview_only: print("\n当前为预览模式,未实际执行任何重命名操作。如需执行,请将 preview_only 设置为 False。")
接下来是 parse_and_construct_new_name
这个核心函数,它负责解析旧文件名并构建新文件名。这是最考验脚本健壮性的地方,因为文件名格式五花八门。
def parse_and_construct_new_name(filename): """ 尝试解析文件名,并根据预设规则构建新的文件名。 目前支持简单的剧集和电影解析。 """ name, ext = os.path.splitext(filename) new_name_parts = {} # 尝试解析剧集 (SXXEXX, SXX_EXX, XXxYY, etc.) # 示例:Show.Name.S01E05.Episode.Title.1080p.WEB-DL-GROUP.mkv # 示例:Show Name 1x05 Episode Title.mp4 # 示例:Show Name - Season 1 Episode 5.mkv tv_patterns = [ re.compile(r'^(.*?)[.\s_-][Ss](\d{1,2})[Ee](\d{1,2})(.*)$', re.IGNORECASE), # S01E01 re.compile(r'^(.*?)[.\s_-](\d{1,2})[Xx](\d{1,2})(.*)$', re.IGNORECASE), # 1x01 re.compile(r'^(.*?)[.\s_-]Season[.\s_-]?(\d{1,2})[.\s_-]Episode[.\s_-]?(\d{1,2})(.*)$', re.IGNORECASE) # Season 1 Episode 1 ] for pattern in tv_patterns: match = pattern.match(name) if match: show_name = match.group(1).replace('.', ' ').strip() season = int(match.group(2)) episode = int(match.group(3)) # 尝试从剩余部分提取剧集标题,这部分会比较复杂 # 简单处理:如果剩余部分有明显的标题,就取之,否则忽略 remaining_part = match.group(4).replace('.', ' ').strip() episode_title = "" # 粗略判断是否包含有效标题信息,避免把分辨率、组名等当作标题 if len(remaining_part) > 5 and not any(res in remaining_part.lower() for res in ['720p', '1080p', '2160p', 'hdtv', 'web-dl', 'bluray', 'x264', 'x265']): episode_title = re.split(r'(\d{3,4}p|WEB-DL|HDTV|BluRay|x264|x265|-GROUP)', remaining_part, flags=re.IGNORECASE)[0].strip() if episode_title and len(episode_title) > 3: # 避免提取到无意义的短字符串 episode_title = ' - ' + episode_title else: episode_title = "" # 没提取到有效标题就清空 # 清理剧集名称,移除年份或不必要的后缀 show_name = re.sub(r'(\d{4})', '', show_name).strip() # 移除可能的年份 show_name = re.sub(r'(WEB-DL|HDTV|BluRay|x264|x265|GROUP|REPACK)', '', show_name, flags=re.IGNORECASE).strip() show_name = re.sub(r'(\s*-\s*)$', '', show_name) # 移除末尾的短横线 new_filename = f"{show_name} - S{season:02d}E{episode:02d}{episode_title}{ext}" return new_filename.replace(' ', ' ').strip() # 移除多余空格 # 尝试解析电影 (Movie.Name.2023.1080p.WEB-DL-GROUP.mkv) # 电影解析相对简单,主要是提取片名和年份 movie_pattern = re.compile(r'^(.*?)[.\s_-](\d{4})(.*)$', re.IGNORECASE) # 电影名.年份 match = movie_pattern.match(name) if match: movie_name = match.group(1).replace('.', ' ').strip() year = match.group(2) # 清理电影名称,移除不必要的后缀 movie_name = re.sub(r'(WEB-DL|HDTV|BluRay|x264|x265|GROUP|REPACK)', '', movie_name, flags=re.IGNORECASE).strip() movie_name = re.sub(r'(\s*-\s*)$', '', movie_name) new_filename = f"{movie_name} ({year}){ext}" return new_filename.replace(' ', ' ').strip() # 如果以上模式都不匹配,尝试清理常见垃圾信息 cleaned_name = re.sub(r'(\d{3,4}p|WEB-DL|HDTV|BluRay|x264|x265|GROUP|REPACK|Multi|CHS|ENG|\[.*?\]|\(.*?\)|\{.*?\})', '', name, flags=re.IGNORECASE) cleaned_name = cleaned_name.replace('.', ' ').strip() cleaned_name = re.sub(r'\s+', ' ', cleaned_name).strip() # 移除多余空格 # 如果清理后文件名变得很短或无意义,可能还是无法解析 if len(cleaned_name) < 3: return None # 无法有效解析 # 最后尝试加上原始扩展名 return cleaned_name + ext
要运行这个脚本,你只需要在主程序里调用 standardize_media_filenames
函数,传入你的媒体库根目录即可。

# 示例用法: # 将 'Your/Media/Library/Path' 替换为你的实际路径 # standardize_media_filenames('/Volumes/Media/TV Shows', preview_only=True) # standardize_media_filenames('/Volumes/Media/Movies', preview_only=False)
为什么我们需要标准化影视剧文件命名?这不仅仅是强迫症
坦白说,最初我开始折腾这些,确实有那么点“整理癖”的成分。看到下载回来的文件,有的叫[某某字幕组]神剧.S01E01.XXP.mkv
,有的叫ShenJu.1x01.WebDL.mp4
,甚至还有直接就是ep1.rmvb
这种,就觉得头大。但很快我就发现,这不仅仅是视觉上的整洁问题,更是实用性的大幅提升。
最直接的好处是媒体服务器的体验。像Plex、Jellyfin、Kodi这类家庭影音中心软件,它们要从网上抓取电影海报、剧集简介、演员信息这些元数据,极度依赖文件的命名规范。如果你的文件名是S01E01
,它们能轻易识别出是《神剧》的第一季第一集;但如果叫ep1
,那它们就抓瞎了,你只能看到一个光秃秃的文件名,没有海报,没有剧情,体验大打折扣。
再者,手动查找和管理也变得异常轻松。想找《某某剧》的第五集?直接搜索某某剧 S01E05
就行,而不是在茫茫文件中大海捞针。这省下的时间,远比你想象的要多。它是一种数字生活的“基建”,一开始投入点精力,后面就能持续享受便利。
Python脚本如何识别并解析复杂的影视剧文件名?核心逻辑拆解
解析文件名,就像是给文件做“DNA鉴定”。我们手上的文件名,往往是各种信息混杂的字符串:剧名、季数、集数、分辨率、编码格式、发布组、甚至还有字幕组信息。Python的re
模块,也就是正则表达式,是完成这项任务的利器。
核心思路是定义一系列“模式”,然后用这些模式去匹配文件名。
1. 剧集模式:
剧集文件名通常包含季(Season)和集(Episode)的标识。常见的有SXXEXX
、XXxYY
。
S01E05
:[Ss](\d{1,2})[Ee](\d{1,2})
。\d{1,2}
表示匹配1到2位数字,[Ss]
和[Ee]
则匹配大小写不敏感的'S'和'E'。1x05
:(\d{1,2})[Xx](\d{1,2})
。类似,只是分隔符是x
。
当我们匹配到这些模式后,就可以提取出剧名(通常是模式前缀的部分)、季数和集数。但要注意,剧名本身可能也包含.
、-
等分隔符,需要进一步清理。比如The.Good.Doctor.S01E01.mkv
,提取出来The.Good.Doctor
,就需要把它替换成The Good Doctor
。
2. 电影模式: 电影文件通常包含片名和年份。
Movie.Name.2023.1080p.mkv
:^(.*?)[.\s_-](\d{4})(.*)$
。这里(\d{4})
用来匹配四位年份。
解析电影比剧集简单,因为通常没有季集概念。主要就是提取片名和年份。
3. 垃圾信息过滤:
文件名里除了核心信息,还常常夹杂着分辨率(1080p
、720p
)、编码(x264
、x265
)、发布组名(GROUP
)、视频源(WEB-DL
、BluRay
、HDTV
)等。这些信息对命名标准化来说是“噪音”,需要用正则表达式把它们剔除。
# 常见的垃圾信息模式 junk_patterns = [ r'(\d{3,4}p)', # 720p, 1080p, 2160p r'(WEB-DL|HDTV|BluRay|BDRip|DVDRip)', # 视频源 r'(x264|x265|HEVC|AVC)', # 编码 r'(AAC|AC3|DTS|FLAC)', # 音频编码 r'(GROUP|REPACK|PROPER|RERIP)', # 发布组或版本修正 r'(Multi|CHS|ENG|JPN|KOR)', # 多语言或字幕语言 r'\[.*?\]', # 方括号内的内容 r'\(.*?\)', # 圆括号内的内容 r'\{.*?\}', # 花括号内的内容 r'\s*-\s*$' # 结尾的横线 ] # 组合这些模式,用或操作符 | combined_junk_pattern = re.compile('|'.join(junk_patterns), re.IGNORECASE) # 清理函数示例 def clean_name_part(text): text = combined_junk_pattern.sub('', text) # 替换垃圾信息为空 text = text.replace('.', ' ').replace('_', ' ').strip() # 点和下划线替换为空格 text = re.sub(r'\s+', ' ', text).strip() # 移除多余空格 return text
实际应用中,解析的顺序也很重要。通常会先尝试剧集模式,如果匹配失败,再尝试电影模式,最后才是通用的清理。因为剧集模式更具体,能避免电影文件被误判为剧集。这个过程充满试错,没有一个万能的正则表达式能解决所有问题,所以代码里会包含多个模式尝试匹配,体现了一种“尽力而为”的策略。
处理命名冲突与预览:安全重命名策略
直接对文件进行操作,风险是存在的。万一脚本出错了,或者解析逻辑不完善,把文件改得面目全非,那就麻烦了。所以,一个健壮的重命名脚本,必须考虑安全性和可控性。
1. 预览模式(Dry Run):
这是最基本也是最重要的安全措施。在实际执行重命名之前,脚本应该能够只打印出它“打算”怎么改,而不真正动文件。这样你就能提前发现问题,比如文件名解析错误、新文件名不符合预期等。我的脚本中preview_only=True
就是这个作用。在确认一切无误后,再把这个参数设为False
。
2. 命名冲突处理:
当你尝试将文件A.mkv
重命名为Movie Name (2023).mkv
时,如果目录下已经存在一个同名的Movie Name (2023).mkv
,怎么办?
- 跳过(Skip): 这是最安全的做法。如果目标文件名已存在,就直接跳过这个文件,不进行任何操作。这避免了意外覆盖,但可能导致部分文件未能按预期命名。
- 追加序号(Append Number): 比如,
Movie Name (2023) (1).mkv
。这适用于你可能确实有同一个电影的多个版本(比如不同分辨率)。 - 覆盖(Overwrite): 最危险的做法,强烈不推荐。除非你非常清楚你在做什么,否则不要选择这种方式,它会无情地删除旧文件。
我的脚本选择了“跳过”策略,因为对于媒体文件来说,很少需要强制覆盖,更多是希望避免重复。
3. 错误日志与未处理文件: 不是所有文件都能被完美解析。有些文件名可能太过奇葩,或者根本不符合任何已知模式。对于这些无法解析或重命名的文件,脚本应该能够记录下来,而不是默默跳过。这样,你就可以在脚本运行结束后,查看日志,手动处理那些“顽固分子”。这就像是给你的媒体库做了一次体检,哪些是健康合格的,哪些是需要人工干预的,一目了然。
4. 目录结构考虑:
有时候,我们不仅想重命名文件,还想重命名包含剧集或电影的文件夹。例如,把The.Good.Doctor.Season.1
改成The Good Doctor (2017) - Season 01
。这涉及到对os.walk
遍历出的dirnames
进行操作,并且需要更复杂的逻辑来判断目录是否应该被重命名。我的示例脚本只处理了文件,但扩展到目录重命名也是完全可行的,只是需要更谨慎地处理路径依赖。
总的来说,一个好的自动化工具,
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
334 收藏
-
487 收藏
-
389 收藏
-
310 收藏
-
333 收藏
-
491 收藏
-
153 收藏
-
158 收藏
-
486 收藏
-
127 收藏
-
280 收藏
-
129 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 511次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 498次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习