实现代码
援用所需模块import re # 正则表达式
mp3信息和门路提取def mp3Info(input_file_url):
# 读取mp3文件input_file_url = input_file_urlwith open(input_file_url, "rb") as input_file: mp3_data = input_file.read().hex()# 判断mp3文件类型是否是 ID3v2.3 格局if mp3_data[:6] == "494433" and mp3_data[6:8] == "03": print("歌曲是ID3v2.3版本,正在提取信息...") # 获取歌曲名称 if re.search(r"\\", input_file_url): input_file_name = re.search("(.*).mp3", input_file_url.split("\\")[-1]).group(1) else: input_file_name = re.search("(.*).mp3", input_file_url).group(1) # 获取歌曲门路 if re.search("(.*)" + input_file_name + ".mp3", input_file_url): input_file_path = re.search("(.*)" + input_file_name + ".mp3", input_file_url).group(1) else: input_file_path = "" return mp3_data, input_file_path, input_file_name # 返回 mp3 16进制数据,输出文件门路,输出文件文件名else: return ""
提取标签内容函数def tagInfo(tag_name, mp3_data):
# 标签名称,mp3残缺数据tag_name, mp3_data = tag_name, mp3_data# 标签列表tag_name_list = {"TIT2": "54495432", "TPE1": "54504531", "TALB": "54414c42"}if tag_name in tag_name_list: tag_hex = tag_name_list[tag_name] # 标签的 16 进制数据 # 标签长度 tag_len = int(re.search(tag_hex + "(.{8})", mp3_data).group(1), 16) # print("%s 标签的长度是 %s 个字节" % (tag_name,tag_len)) # 判断标签类型 tag_index = mp3_data.find(tag_hex) tag_data_type = mp3_data[(tag_index + 2 * (4 + 4 + 2)):(tag_index + 2 * (4 + 4 + 2 + 1))] # 判断内容编码方式 if tag_data_type == "00": encoding_type = 'iso8859-1' # print("采纳 ISO-8859-1 编码 ") if tag_data_type == "01": encoding_type = 'utf-16-le' # print("采纳 UTF-16LE 编码 ") elif tag_data_type == "02": encoding_type = 'utf-16-be' # print("采纳 UTF-16BE 编码 ") # elif tag_data_type == "03": # (仅ID3V2.4才反对) # encoding_type = 'utf-8' # print("采纳 UTF-8 编码 ") # 提取标签内容 tag_data_hex = mp3_data[(tag_index + 2 * (4 + 4 + 2 + 1)):( tag_index + 2 * (4 + 4 + 2 + 1) + tag_len * 2 - 2)] # 取标签内容(16进制) tag_data_bytes = bytes.fromhex(tag_data_hex) # 将字符串转换为字节流数据 tag_info = tag_data_bytes.decode(encoding_type, 'ignore') # 依据编码类型解码 return tag_info # 返回标签的内容else: return ""
提取所需标签信息def tagsInfo():
# 标签类型 TIT2:题目,TPE1:艺术家,TALB:专辑tags = {"TIT2": "歌名", "TPE1": "歌手", "TALB": "专辑"}# 标签内容提取tags_info = {}for i in tags: tag_name = i tag_info = tagInfo(tag_name, mp3_data) # 标签数据 tags_info[tags[i]] = tag_info.encode('utf-8').decode('utf-8-sig') # 应用utf-8-sig编码,否则呈现'\ufeff' BOM数据return tags_info # 返回所有标签的内容
获取歌曲时长函数def mp3Duration(mp3_data):
music_index = mp3_data.find("496e666f0000000f") # 定位歌曲理论的起始地位music_size = len(mp3_data[music_index:]) / 2 # 歌曲字节长度duration = music_size * 8 / (128 * 1000) # 获取歌曲时长,单位 sduration_show = str(int(duration / 60)) + ":" + str(int(duration % 60)) # 格式化歌曲时长return duration_show # 返回格式化的歌曲时长
提取图片函数def imgTag(mp3_data, input_file_path, input_file_name):
# 歌曲数据,输出文件的门路,输出文件的文件名mp3_data, input_file_path, input_file_name = mp3_data, input_file_path, input_file_name# 图片数据的提取img_data_hex = re.search(r"ffd8.+?496e666f0000000f", mp3_data)[0] # 图片的 16 进制数据if img_data_hex: img_data_bytes = bytes.fromhex(img_data_hex) # 将字符串转换为字节流数据 out_file_name = input_file_path + input_file_name + '.jpg' with open(out_file_name, "wb") as out_file: out_file.write(img_data_bytes) return "%s%s.jpg" % (input_file_path, input_file_name)else: return ""
if name == '__main__':
try: # 提示信息 print("##### 本程序为提取 mp3 ID3v2.3 格局的歌曲信息 #####") # mp3门路 input_file_url = input("请输出须要提取的文件门路:") # 获取歌曲信息 mp3_info = mp3Info(input_file_url) if mp3_info: # 获取文件门路,文件名 mp3_data, input_file_path, input_file_name = mp3_info # 返回 mp3 16进制数据,输出文件门路跟单网www.gendan5.com/,输出文件文件名 # 获取标签数据 tags_info = tagsInfo() # 获取歌曲时长信息 mp3_duration = mp3Duration(mp3_data) tags_info["时长"] = mp3_duration # 增加时长字段 # 获取图片数据 imgInfo = imgTag(mp3_data, input_file_path, input_file_name) tags_info["图片门路"] = imgInfo # 增加图片字段 print(tags_info) # 日志信息 log = "歌曲门路: " + input_file_path + input_file_name + ".mp3 \n" + "歌曲信息:" + str( tags_info) + "\n\n" else: # 日志信息 log = "暂不反对此文件的提取,本程序仅反对 ID3v2.3 格局的 mp3 文件\n\n" print("暂不反对此文件的提取,本程序仅反对 ID3v2.3 格局的 mp3 文件")except: # 日志信息 log = "意外谬误\n\n" print("意外谬误")finally: # 保留日志 with open(r"log.txt", "a") as out_file: out_file.write(log)