Привет всем! Не так давно в Facebook возникло обсуждение — как навести порядок в библиотеке на локальном устройстве? Учитывая, что в основном читаю я файлы .fb2 — сегодняшний вопрос будет звучать как решение проблемы: извлекаем данные из файла .fb2. А заодно порядок на винте наводим 🙂
Суть проблемы: когда качаем книгу — чаще всего она имеет совершенно ненормальное название (например: Piz_Novyy-yazyk-telodvizheniy.RoTD5Q.393030.fb2 — да, в целом, понятно, но все же …). Учитывая, что по этой крякозябре сложно догадаться, о чем идет речь — возник вопрос, а можно ли как-то определить автора, название, и соответствующим образом переименовать файл? Вполне возможно!
Итак, что такое файл .fb2? Фактически — это .xml документ. А раз это .xml документ — то его можно и нужно распарсить 🙂
Проблема, с которой я столкнулся в самом начале — определить кодировку файла. В теории — можно было наобум открывать файл в любой кодировке, искать заголовок кодировки внутри самого файла, и исходя из этого работать далее. Но код получался таким большим, что пришлось использовать библиотеку chardet, которая работает со следующими кодировками:
В итоге код берет .fb2 файл, разбирает его, находит автора книги, название книги и сохраняет этот файл в видео «Автор-Название». Можно, конечно, добавить жанр, и прочее. Проверил код на работоспособность на паре тысяч книг, имеющихся в наличии. Вроде как работает.
Сам код в полном виде выглядит так:
-
from chardet.universaldetector import UniversalDetector #Определим кодировку файла
-
import re #Подключаем библиотеку для парсинга
-
import glob #Подключаем библиотеку для работы с файлами определенного расширения
-
import os #Подключаем библиотеку для работы с файловой системой
-
import random
-
-
path = str(input('Где находятся исходные файлы? : \n'))
-
regxp = '[\w-]+[\w:]'
-
result = re.findall(regxp, path) #Разбиваем введенный адрес на составляющие без обратного слеша
-
path = '\\\\'.join(result) #Добавляем двойной слеш после каждой папки (под формат Python)
-
-
print('Берем данные из:', path)
-
os.chdir(path)
-
print('Предстоит обработать книг:', len(glob.glob('*.fb2')))
-
for file in glob.glob('*.fb2'):
-
print('\n\nОбрабатываем файл:',file)
-
detector = UniversalDetector()
-
with open(file, 'rb') as file_encoding:
-
for line in file_encoding:
-
detector.feed(line)
-
if detector.done:
-
break
-
detector.close()
-
file_encoding = str(detector.result['encoding'])
-
print(file_encoding)
-
if file_encoding == False:
-
continue
-
else:
-
with open(file, 'r', encoding=file_encoding) as file_name:
-
stroke = file_name.read()
-
stroke = str(stroke)
-
reg_genre = '<genre>(.+)</genre>'
-
reg_title = '<book-title>(.+)</book-title>'
-
reg_last_name = '<last-name>(.+)</last-name>'
-
reg_first_name = 'first-name>(.+)</first-name>'
-
reg_trial = '<title>Конец ознакомительного фрагмента.</p></title>'
-
title = re.findall(reg_title, stroke)
-
title = str(title)
-
title = title.replace('\'', '').replace('\"', '').replace(':', '').replace('#', '').replace('(', ''). \
-
replace(')', '').replace('[', '').replace(']', '').replace('!', '').replace('?', '').replace('\\', '').\
-
replace('/', '').replace('.', '').replace('«', '').replace('»', '').replace(',', '').replace('-', '')
-
-
last_name = re.findall(reg_last_name, stroke)
-
print('Фамилия после поиска первой регуляркой: ', last_name )
-
print('Тип фамилии:', type(last_name))
-
if len(last_name) > 0:
-
last_name = last_name[0]
-
last_name = ''.join(last_name)
-
last_name = str(last_name)
-
else:
-
last_name = str('БезФамилии')
-
print('Фамилия после уборки лишних знаков: ', last_name)
-
print('Тип фамилии:', type(last_name))
-
reg_last_names = '^\w*'
-
last_name = re.findall(reg_last_names, last_name)
-
print('Фамилия после поиска второй регуляркой: ', last_name)
-
print('Тип фамилии:', type(last_name))
-
last_name = str(''.join(last_name))
-
-
first_name = re.findall (reg_first_name, stroke)
-
print('Результат имени после работы первой регулярки: ', first_name)
-
print('Тип имени: ', type(first_name))
-
if len(first_name) > 0:
-
first_name = first_name[0]
-
first_name = ''.join(first_name)
-
first_name = str(first_name)
-
else:
-
first_name = str('БезИмени')
-
print('Имя после уборки лишних знаков: ', first_name)
-
reg_first_names = '^\w*'
-
first_name = re.findall(reg_first_names, first_name)
-
print('Имя после обработки второй регуляркой: ', first_name)
-
print('Тип имени: ', type(first_name))
-
first_name = str(''.join(first_name))
-
-
trial_status = re.findall(reg_trial, stroke)
-
print('Demo? ',trial_status)
-
trial_status = ''.join(trial_status)
-
print(trial_status)
-
print(type(trial_status))
-
print('Название:', ''.join(title))
-
print('Фамилия: ', last_name)
-
title = str(''.join(title))
-
print('Имя: ', first_name)
-
-
if trial_status == '<title><p>Конец ознакомительного фрагмента.</p></title>':
-
print('Файл будет переименован: ', 'Demo' + ' ' + last_name + ' ' + first_name + ' ' + title + '.fb2')
-
new_file_name = str('Demo' + ' ' + last_name + ' ' + first_name + ' ' + title + '.fb2')
-
try:
-
os.rename(str(file), new_file_name)
-
except:
-
os.rename(str(file), 'copy ' + new_file_name)
-
else:
-
print('файл будет переименован: ', last_name + ' ' + first_name + ' ' + title + '.fb2')
-
new_file_name = str(last_name + ' ' + first_name + ' ' + title + '.fb2')
-
try:
-
os.rename(str(file), new_file_name)
-
except:
-
os.rename(str(file), 'copy ' + str(random.randrange(1, 10000)) + new_file_name)
-
-
print('Все сделано!')
Так же код доступен на GitHub по ссылке.
И как всегда — в случае возникновения вопросов и комментариев или даже идей — пишите на почту или в Telegram 🙂