
В этой статье мы хотели бы поделиться кейсом о том, как собрать документацию по проектам заказчика с помощью Сonfluence.
Скорее всего вы знаете, что такое Confluence и для чего он нужен. Если нет, коротко скажем, что это пространство/сайт, где вы копите все знания о вашей деятельности в организации. То есть, например, выполняя какой-либо проект, параллельно ведете свой раздел в Confluence, чтобы новый сотрудник смог быстрее в нем разобраться. Также это мощный инструмент для различной аналитики, ведения статистики, но, если вам потребуются дополнительные инструменты и «фишки», нужно будет их оплатить, так как они не будут доступны в бесплатной версии.
Специалист Neoflex из подразделения Big Data Solutions рассказывает о проблеме, с которой он столкнулся:
При введении своего раздела в Confluence стараешься сразу же описывать документацию для клиента (руководство администратора), а вот забрать/экспортировать страницу в Word получается только по одной странице, и приходилось объединять все это руками в один документ. Поэтому я приступил к реализации своего микросервиса по сбору документов и созданию документации.
Зная такие инструменты как Selenium и язык программирования Python, мною была написана рекурсивная функция от нужного отдела по всем его дочерним объектам. В ходе выполнения наткнулся на большое количество проблем: например, отсутствие id в url, принадлежность одной страницы другому разделу, медленная работа, несоответствие стилей и т.д. Вся работа строилась на простом алгоритме: проходить все страницы, сохранять необходимый текст в тегах в html файл для дальнейшего преобразования в DOCX. Почему пришлось отказаться от данного подхода:
-
Время работы. Selenium необходимо открыть страницу и посмотреть определенные теги. Обычно используют sleep() для того, чтобы страница прогрузилась;
-
Сложность самого Confluence. Он не показывает вложенные объекты в подразделе пока не будет выбран данный раздел (ниже приведен пример);
-
Разметка таблиц, заголовки, артефакты по тексту (в конце страницы, где была таблица, вставляется строка с функциями над таблицами в Сonfluence);
-
И самое главное – это отсутствие картинок.
После этого я вернулся к поиску уже готовых решений в интернете и нашел Confluence API. Это и положило новое начало в разработке инструмента. Все, что мне нужно было сделать для работы – это скачать библиотеку, подключиться через логин и пароль, указать начальное пространство для работы скрипта.
Нам понадобится установить библиотеку atlassian-python-api и уже можно работать с данным API.
Документация по API довольно большая, но мне пригодится лишь пара команд (для ознакомления можно почитать данный ресурс).
Для подключения достаточно написать код:
from atlassian import Confluence url='https://confluence.ru/'#ссылка на начальную страницу. username='твой_логин' password='твой_пароль' confluence = Confluence( url=url, username=username, password=password)
Далее необходимо получить дочерние страницы и скачать файлы.
Весь код с комментариями представлен ниже:
from atlassian import Confluence def get_id(url_full): return url_full.split('=')[-1] def get_child(id): t = confluence.cql(cql='parent={0}'.format(id), start=0, limit=None, expand=None,include_archived_spaces=None, excerpt=None)['results'] return sort_json(t) def cursor(list_child,level=0): for i in list_child: id = i['content']['id'] #проверка на наличие дочерних элементов if len(get_child(id))>0: page = confluence.get_page_by_id(page_id=id) response = confluence.get_page_as_word(page['id']) contents.append(response) #проходим снова в рекурсию cursor(get_child(id),level=level+1) else: page = confluence.get_page_by_id(page_id=id) response = confluence.get_page_as_word(page['id']) contents.append(response) def start_parser(url,url_full): #Получили ID родителя id_url = get_id(url_full) #получаем содержимое страницы page = confluence.get_page_by_id(page_id=id_url) #сохраняем вордовский контент страницы(экспорт страницы) response = confluence.get_page_as_word(page['id']) contents.append(response) #Получаем вложенные объекты list_child = get_child(id_url) #начинаем рекунсию cursor(list_child) return page['title'] def save_files(contents): for i,j in enumerate(contents): with open(f'{i}.doc', mode='wb') as file_pdf: file_pdf.write(j) def sort_json(json_list): titles = list() for i in json_list: titles.append(i['title']) titles.sort() sort_json = list() for i in titles: for j in json_list: if i==j['title']: sort_json.append(j) return sort_json url='https://confluence.ru/' url_full='https://confluence/pages/viewpage.action?pageId=*******' confluence = Confluence( url=url, username='твой_логин', password='твой_пароль') contents = list() #начало работы по сбору страниц global_title = start_parser(url,url_full) #загрузка страниц в doc файлы save_files(contents)
На текущий момент у нас собираются все дочерние элементы и скачиваются в корневую папку файлы DOC, которые нужно преобразовать в DOCX. С этим мне помогла стандартная библиотека win32com.
На вход подается список путей к файлам DOC:
def convert_doc_to_docx(files): for path in files: word = win32.gencache.EnsureDispatch('Word.Application') doc = word.Documents.Open(path) doc.Activate() # переименовываем файлы в docx. new_file_abs = os.path.abspath(path) new_file_abs = re.sub(r'\.\w+$', '.docx', new_file_abs) # сохраняем и закрываем word.ActiveDocument.SaveAs( new_file_abs, FileFormat=constants.wdFormatXMLDocument ) doc.Close(False) os.remove(path)
Конвертировать файлы требуется для дальнейшей работы библиотекой python-docx, которая будет склеивать все документы между собой, а также для сохранения всех стилей.
На вход подается список имен файлов
def composer(files): master = Document('qwe.docx') composer = Composer(master) for file in files: doc2 = Document(file) if file != files[-1]: doc2.add_page_break() composer.append(doc2) composer.save(f"{global_title}.docx")
Разберем подробнее:
-
master = Document('qwe.docx')– это подготовленный ранее мною шаблон со стилями, и шаблон визуального оформления страницы. Сюда мы и будем «дергать» по очереди каждый файл и добавлять разделение страниц; -
composer = Composer(master)– выбираем master файл как целевой и будем именно в него добавлять другие файлы docx; -
doc2.add_page_break()– данная функция позволяет вставить «разрыв страницы», чтобы отделить разделы между собой; -
composer.append(doc2)– добавляем информацию с doc2 в целевой раздел; -
composer.save (f"{global_title}.docx")– по завершению сохраняем файл с наименованием, которое получили в самом начале алгоритма сбора документации.
В итоге мы получили файл DOCX со всеми вложенными страницами по разделу проекта с Confluence. Сохранили все картинки, таблицы и стили, а также добавили свой шаблон для визуального оформления страниц в Word.
Подводя итоги, можно считать, что данный инструмент получился полезным. Мы использовали API для получения дочерних элементов и скачивания страницы из раздела, а также библиотеку python-docx для сбора всех файлов в один – целевой и ранее созданный шаблон под клиентов.
Весь код выложен в github
ссылка на оригинал статьи https://habr.com/ru/company/neoflex/blog/659319/
Добавить комментарий