Форум сайта python.su
Добрый день.
Есть задача: брать данные из экселя, вставлять их в заранее подготовленную шаблон для награждения и потом готовые листы объединять в один документ. С грехом пополам, пользуясь разными источниками написал вот такой скрипт. Всё, вроде бы, нормально и отдельные листы выглядят как и было задумано. Но при объединении, дальше первого листа, весь текст начинает переезжать. Может кто-нибудь подсказать в чём может быть дело? Спасибо.
import openpyxl import os from docxtpl import DocxTemplate from docx import Document from docx.shared import Cm from docxcompose.composer import Composer from docx import Document as Document_compose from pathlib import Path ############################################################### source_folder = './result/' # Путь к папке с исходными файлами destination_folder = './result/сводные/' # Путь к папке, в которую будут сохранены сводные файлы final_doc_name = 'сводный.docx' xls_name = './tpl/real_data_cut.xlsx' gbou_name = './tpl/gbou.txt' docx_tpl = './tpl/tpl3.docx' # Отступы в docx шаблоне top = 0.75 bottom = 0.5 left = 1.27 right = 1.27 ################################################################## def xls2doc(): # загружаем файл excel workbook = openpyxl.load_workbook(xls_name) # выбираем первую страницу worksheet = workbook.active # открываем файл с названиями школ with open(gbou_name, encoding='utf-8') as f: schools = [line.strip().split(';') for line in f] # определяем номера столбцов по заголовкам header_row = 1 last_col = worksheet.max_column headers = {} for col in range(1, last_col+1): cell = worksheet.cell(row=header_row, column=col) if cell.value: headers[cell.value] = col # проходим по каждой строке данных for row in range(header_row+1, worksheet.max_row+1): # получаем значения всех полей last_name = worksheet.cell(row=row, column=headers['Фамилия']).value first_name = worksheet.cell(row=row, column=headers['Имя']).value middle_name = worksheet.cell(row=row, column=headers.get('Отчество')).value full_name = f'{last_name} {first_name}' if middle_name: full_name += f' {middle_name}' sex = worksheet.cell(row=row, column=headers['Пол']).value if sex and sex[0] in ['Ж', 'ж']: sex = 'учащаяся' elif sex and sex[0] in ['М', 'м']: sex = 'учащийся' else: sex = 'неизвестно' school_name = worksheet.cell(row=row, column=headers['Полное название общеобразовательного учреждения']).value school_num = '' if school_name: school_num = [s for s in school_name.split() if s.isdigit() or s == 'Морская'] if school_num: school_num = school_num[0] gbou = '' for school in schools: if school_num in school[0]: gbou = school[1] break discipline = worksheet.cell(row=row, column=headers['Предмет']).value class_num = worksheet.cell(row=row, column=headers['Класс обучения']).value status = worksheet.cell(row=row, column=headers['Статус участника']).value teacher = worksheet.cell(row=row, column=headers['Фамилия, Имя, Отчество учителя']).value # Открываем шаблон документа и рендерим его с помощью данных из строки tpl = DocxTemplate(docx_tpl) context = { 'full_name': full_name, 'sex': sex, 'class_num': class_num, 'gbou': gbou, 'status': status, 'discipline': discipline, 'teacher': teacher } tpl.render(context) # Сохраняем сгенерированный документ в файл с именем, соответствующим значению поля name tpl.save(f'./Result/{full_name}.docx') def create_master_docx(path: Path): # Создаем новый документ doc = Document() # Устанавливаем поля sections = doc.sections for section in sections: section.top_margin = Cm(top) section.bottom_margin = Cm(bottom) section.left_margin = Cm(left) section.right_margin = Cm(right) # Устанавливаем размер страницы в А4 section = sections[0] section.page_height = Cm(29.7) section.page_width = Cm(21.0) # Сохраняем сводный файл в папку назначения doc.save(os.path.join(destination_folder,final_doc_name)) def merge_docx(path_master: destination_folder, files: list): """ Открываем файл в который будем объединять все остальные. Создаем композитора. Запускаем цикл по списку файлов. Добавляем в композитор содержимое каждого файла из списка. Сохраняем итоговый документ. """ number_of_sections = len(files) master = Document_compose(path_master) composer = Composer(master) for i in range(0, number_of_sections): doc_temp = Document_compose(files[i]) composer.append(doc_temp) composer.save(path_master) def main(): """ Запрашиваем имя для объединенного файла. Запрашиваем путь к директории с файлами для объединения. Проверяем существование директории и является ли переданный путь путем к директории. Получаем список файлов в директории, формируем список файлов с полным путем к ним. Создаем новый документ. Объединяем документы из директории. """ xls2doc() path = Path.cwd() files = [Path(source_folder) / x for x in os.listdir(source_folder) if Path(x).suffix == ".docx"] if files: create_master_docx(destination_folder) merge_docx(os.path.join(destination_folder, final_doc_name), files) print(f"Объединение завершено. Объединенный файл -> {os.path.join(destination_folder, final_doc_name)} ") else: print("Файлов для объединения не найдено") if __name__ == "__main__": main()
Отредактировано crewdk (Апрель 2, 2023 13:15:44)
Офлайн
crewdkТеперь их по отдельности переводи в pdf, а потом эти листы в pdf соединяй в один pdf.
С грехом пополам, пользуясь разными источниками написал вот такой скрипт. Всё, вроде бы, нормально и отдельные листы выглядят как и было задумано.
crewdkДа там много в чём может быть дело. Другие шрифты, форматы документов, настройки программы для просмотра и тому подобное. Также сами модули в языках программирования бывают несовершенными и глючными. В любом случае ты даже вручную если будешь это объединять, то на каком-нибудь компе оно съедет куда-нибудь не туда. Так что лучше пользоваться тем, что не зависит от этих меняющихся характеристик. Поэтому надо использовать pdf, который везде выглядит одинаково после его создания. Для этого он и создавался, для этого его и придумали.
Но при объединении, дальше первого листа, весь текст начинает переезжать. Может кто-нибудь подсказать в чём может быть дело?
Отредактировано py.user.next (Апрель 2, 2023 18:56:43)
Офлайн
Спасибо за ответ. К сожалению, в этих наградных грамотах есть картинка-подложка и при сохранении в pdf качество этой картинки очень сильно ухудшается. Рабочего варианта перевода без потери качества из word в pdf найти так и не смог. Может сможете навскидку подсказать в какую сторону копать?
Офлайн
crewdkЗвучит бредово. Как ты сохраняешь docx в pdf? Надеюсь, не через какое-нибудь облако Яндекс или что-то наподобие.
и при сохранении в pdf качество этой картинки очень сильно ухудшается
crewdkТак ты пиши, что ты нашёл. Может, ты этим просто пользоваться не умеешь.
Рабочего варианта перевода без потери качества из word в pdf найти так и не смог.
crewdkЧто это значит? Переезжает куда, в Америку с чемоданами? Переезжать оно может по-разному, штук десять разных переезжаний я тебе могу привести. Про какое из них ты говоришь?
дальше первого листа, весь текст начинает переезжать
crewdkПри каком сохранении? Сохранять можно десятком разных способов.
и при сохранении в pdf
Отредактировано py.user.next (Апрель 2, 2023 20:54:00)
Офлайн
py.user.next
Что это значит? Переезжает куда, в Америку с чемоданами? Переезжать оно может по-разному, штук десять разных переезжаний я тебе могу привести. Про какое из них ты говоришь?
py.user.next
Видно только твой код, который ты выложил, по котором понятно, что ты вообще программировать не умеешь. Мешанина просто какая-то.
import os import win32com.client from docx2pdf import convert word_file_path = 'word.docx' convert(word_file_path) pdf_file_path = os.path.splitext(word_file_path)[0] + '.pdf' word = win32com.client.Dispatch('Word.Application') doc = word.Documents.Open(word_file_path) doc.SaveAs(pdf_file_path, FileFormat=17) doc.Close() word.Quit()
Отредактировано crewdk (Апрель 2, 2023 23:55:21)
Офлайн
crewdkПокажи исправный лист. Как он выглядит?
Для примера, вот так выглядит конец первого листа и конец 8го листа
crewdkВидно, что он сжимает изображение.
А получалось вот так:
... saveOptions.jpeg_quality = 100 ...
Отредактировано py.user.next (Апрель 3, 2023 00:35:41)
Офлайн
Приложи исходные данные, и руками сделай как должно получиться на выходе, выложи сюда.
Офлайн