大家好,我是赛博红兔。我们在刚开始学Python的时候给大伙介绍过,Python有非常多的应用领域,像是这个数据科学、网络爬虫、游戏开发、人工智能、Web开发、办公自动化等等。今天,我们专门来介绍一下Python的办公自动化,这也是我们普通打工人在工作或者生活中使用Python最常见的应用了。
前几天我刚沿着加州一号线,从洛杉矶玩到太浩湖,玩了一趟累个半死不说,打开网盘一看拍了几千张照片,有我自己拍的还有别人拷给我的,全是杂七杂八像是IMG_001.jpg,20231012_123456.jpg,IMG_20231012_123456.jpg,PXL_20231012_123456789.jpg这种手机系统默认的文件命名,没有统一的格式也没有我想要的相片特征信息。起码,如果照片名称带有拍摄的日期,那么在我分拣照片的时候,就会方便不少。总不能每次都靠手工一个个改吧,效率太低,还容易出错。而且,不光是照片,还有视频音频、excel/csv数据文件、pdf和word这样的文档文件。你想,从网上下载了几百甚至几千几万个文件,名称都是一些乱码或者系统默认的名称,我们想要系统的命名方便收藏和归类。类似这种情况,Python的办公自动化就到了出场的时候。今天我在这里抛砖引玉,用Python写个脚本来按照“年-月-日_编号”的格式批量重命名这些常见的办公文件。
首先,我们来看一下用到的库,我们的脚本比较轻量,都是可以用pip直接导入的。没有用到大体量的第三方解析软件,像是解析视频的FFmpeg之类的,大伙可以自行研究拓展。os库是用来获取文件信息、重命名文件。hachoir库用来解析视频和音频文件的元数据(比如说创建日期)。它的体量轻便,支持多种文件格式并且无需解码就能解析元数据。PIL库(也就是Python Imaging Library)主要用来获取图片EXIF数据中的创建日期。PyPDF2库用来专门解析PDF文件。datetime库可以处理日期和时间。
接下来我们来看一些用来解析不同文件类型的功能函数。它们输入的参数都是参数是文件的路径。
第一个是用hachoir库获取视频和音频文件的创建日期。createParser方法能创建一个用于解析视频文件的解析器。我们用文件管理器with语句来打开文件并解析它的元数据。
def get_video_creation_date(filepath):
"""使用hachoir获取视频/音频的拍摄日期"""
try:
parser = createParser(filepath)
if not parser:
print(f"无法解析文件: {filepath}")
return None
with parser:
metadata = extractMetadata(parser)
if metadata:
creation_date = metadata.get('creation_date')
if creation_date:
return creation_date.strftime("%Y-%m-%d")
except Exception as e:
print(f"获取视频/音频拍摄日期失败: {e}")
return None
extractMetadata(parser) 方法从一个解析器对象中提取文件的元数据metadata,这些元数据包括了拍摄日期、修改日期、持续时间、视频/音频的编码格式、分辨率等等信息。这里,我们用metadata.get(‘creation_date’)获得了拍摄日期。如果找到了,就将日期格式化为 年-月-日 这个格式返回。大家可以看到整一个解析文件的过程被异常处理的语句try-except包裹着,方便我们捕获异常并打印错误信息。我会把异常处理的教学视频链接放在下面供大家参考。
第二个是用PIL库来获取图片的拍摄日期。我们用Image.open(filepath)方法打开图像文件。用image._getexif()方法获取图片的EXIF数据。它是一个字典的形式出现。如果存在EXIF数据,继续遍历EXIF数据的键值对。TAGS.get(tag) == ‘DateTimeOriginal’语句是用来查找EXIF标签中是否有表示原始拍摄日期的标签。如果有的话,我们通过datetime.strptime(String Parse Time).strftime (String Format Time)将日期字符串转换为标准日期格式。
def get_image_creation_date(filepath):
"""使用Pillow获取图片的拍摄日期"""
try:
image = Image.open(filepath)
exif_data = image._getexif()
if exif_data:
for tag, value in exif_data.items():
if TAGS.get(tag) == 'DateTimeOriginal':
return datetime.strptime(value, "%Y:%m:%d %H:%M:%S").strftime("%Y-%m-%d")
except Exception as e:
print(f"获取图片拍摄日期失败: {e}")
return None
第三个是使用PyPDF2的PdfReader获取PDF的创建日期。我们先用文件管理器,以二进制方式读取 PDF 文件。然后用PdfReader方法创建一个 PDF 阅读器对象。再从 PDF的元数据中获取创建日期。最后同样我们用datetime库将日期字符串转换为日期对象并格式化。
def get_pdf_creation_date(filepath):
"""使用PyPDF2的PdfReader获取PDF的创建日期"""
try:
with open(filepath, 'rb') as f:
reader = PdfReader(f)
info = reader.metadata
creation_date = info.get('/CreationDate')
if creation_date:
return datetime.strptime(creation_date[2:10], "%Y%m%d").strftime("%Y-%m-%d")
except Exception as e:
print(f"获取PDF创建日期失败: {e}")
return None
第四个是使用系统的创建时间来获取文件的创建日期,主要用来获取CSV、Excel和Word文件的创建日期。这里用os.path.getctime方法获取文件的创建时间。然后用datetime.fromtimestamp方法将时间戳转换为日期对象并格式化。
def get_file_creation_date(filepath):
"""获取CSV、Excel和Word文件的创建日期"""
try:
creation_time = os.path.getctime(filepath)
return datetime.fromtimestamp(creation_time).strftime("%Y-%m-%d")
except Exception as e:
print(f"获取文件创建日期失败: {e}")
return None
最后,我们一起来看一下主函数。我们用来遍历文件夹中的文件,根据不同类型获取创建日期,然后将文件重命名为基于创建日期的格式。首先,我们用supported_extensions这个字典来定义了每种类型的支持扩展名像是mp4,avi一类的视频扩展名,jpg,png一类的照片扩展名。这里我们创建叫existing_names的字典记录每个日期下的文件数量,确保不会产生重复的文件名。接下来,我们遍历文件夹中的所有文件,获取文件的完整路径以及扩展名。之后,根据扩展名判断文件类型,然后调用相应的函数来获取创建日期。如果没有找到拍摄日期,我们就使用系统的文件创建时间。我们不断更新existing_names字典记录每个日期下的文件数量用于作为相同日期下的编号,防止重复的文件名。最后,我们根据创建日期和计数器生成新的文件名,并重命名文件。
def rename_files(folder_path):
"""遍历文件夹中的多种类型文件并重命名"""
supported_extensions = {
'video': ['.mp4', '.mov', '.avi', '.mkv', '.flv'],
'image': ['.jpg', '.jpeg', '.png', '.heic'],
'audio': ['.mp3', '.wav', '.flac'],
'pdf': ['.pdf'],
'csv': ['.csv'],
'excel': ['.xls', '.xlsx'],
'word': ['.doc', '.docx']
}
existing_names = {}
# 遍历所有文件,获取每个文件的完整路径和文件扩展名
for filename in os.listdir(folder_path):
filepath = os.path.join(folder_path, filename)
file_ext = os.path.splitext(filename)[1].lower()
if os.path.isfile(filepath):
creation_date = None
# 根据文件扩展名判断文件类型
if file_ext in supported_extensions['video'] or file_ext in supported_extensions['audio']:
creation_date = get_video_creation_date(filepath)
elif file_ext in supported_extensions['image']:
creation_date = get_image_creation_date(filepath)
elif file_ext in supported_extensions['pdf']:
creation_date = get_pdf_creation_date(filepath)
elif file_ext in supported_extensions['csv'] or file_ext in supported_extensions['excel'] or file_ext in supported_extensions['word']:
creation_date = get_file_creation_date(filepath)
# 如果拍摄日期没有找到,使用文件的创建日期
if not creation_date:
creation_date = get_file_creation_date(filepath)
# 如果找到了创建日期,就进行重命名
if creation_date:
if creation_date not in existing_names:
existing_names[creation_date] = 1
else:
existing_names[creation_date] += 1
new_filename = f"{creation_date}_{existing_names[creation_date]}{file_ext}"
new_filepath = os.path.join(folder_path, new_filename)
# 重命名文件
os.rename(filepath, new_filepath)
print(f"已重命名 {filename} 为 {new_filename}")
在主程序里,if __name__ == “__main__”: 这一部分是 Python 脚本中一个常见的控制结构,它用于判断当前模块是否作为主程序运行。如果成立,下面的主函数就会执行。现在,我们就来分别演示一下批量重命名的效果:照片视频、pdf/word文档、数据文件、音频文件。
if __name__ == "__main__":
rename_files("./files")
这样一来,旅行回来,轻松点击一下,所有照片都按日期分类命名,我们就能轻松知道每张照片是哪天拍的,完全不用担心乱了套。这个Python脚本只有一个最基础功能,大伙可以针对自己的情况对它进行修改和拓展。在评论区大伙也可以聊聊平时用到最多Python自动化的场景是什么呢?好啦,本频道将同步在B站和油管上更新,如果你喜欢我的内容,请不要忘记点赞、订阅和分享,这样就不会错过我更新的内容,欢迎在评论区提出你的想法和建议。今天就到这里,再见吧!

Leave a comment