登录
首页 >  文章 >  python教程

Python批量重命名影视文件实用技巧

时间:2025-07-22 09:36:37 213浏览 收藏

今日不肯埋头,明日何以抬头!每日一句努力自己的话哈哈~哈喽,今天我将给大家带来一篇《Python批量命名影视剧文件技巧》,主要内容是讲解等等,感兴趣的朋友可以收藏或者有更好的建议在评论提出,我都会认真看的!大家一起进步,一起学习!

用Python实现影视剧文件标准化命名的核心步骤是:遍历文件、解析旧名、构建新名、安全重命名;2. 解析依赖正则匹配剧集(SXXEXX/XXxYY)和电影(片名.年份)模式,并清理分辨率、组名等垃圾信息;3. 安全策略包括预览模式确认操作、跳过命名冲突避免覆盖、记录未解析文件便于手动处理,确保自动化过程可靠可控。

如何用Python源码批量命名影视剧文件 Python源码实现文件标准化管理

批量管理影视剧文件,尤其是在命名上,用Python来自动化这个过程简直是把繁琐变成了享受。它能帮助你把那些杂乱无章、下载时带着各种奇怪后缀和编码的文件,整理成一个统一、清晰、便于媒体服务器识别的格式。说白了,就是让你的数字媒体库告别“脏乱差”,变得井井有条。

如何用Python源码批量命名影视剧文件 Python源码实现文件标准化管理

解决方案

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

首先,我们需要一个函数来扫描指定目录下的所有文件。

如何用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 函数,传入你的媒体库根目录即可。

如何用Python源码批量命名影视剧文件 Python源码实现文件标准化管理
# 示例用法:
# 将 '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)的标识。常见的有SXXEXXXXxYY

  • 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. 垃圾信息过滤: 文件名里除了核心信息,还常常夹杂着分辨率(1080p720p)、编码(x264x265)、发布组名(GROUP)、视频源(WEB-DLBluRayHDTV)等。这些信息对命名标准化来说是“噪音”,需要用正则表达式把它们剔除。

# 常见的垃圾信息模式
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学习网公众号。

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>