Преподаватели, работающие в российских ВУЗах, периодически сталкиваются с необходимостью предоставить администрации список своих научных и учебно-методических работ. Например, для (пере)избрания на должность, присвоения звания и т. д. Формат представления информации, форма 16, разработан невесть когда и до сих пор используется в бюрократических недрах Министерства Науки и Высшего Образования РФ. Мне стало лень заполнять эту форму вручную и я написал небольшой python сценарий, который генерирует нужную таблицу на основе информации, полученной из научной электронной библиотеки elibrary.ru. Возможно, кому-то это будет интересно, так что ниже приведено описание этой процедуры...
Итак, для начала нужно зайти на сайт elibrary.ru, авторизоваться,
перейти в раздел авторам и далее в мои публикации. Справа на экране
есть колонка инструменты, в которой есть кнопка Вывести на печать
список публикаций автора. Нажимаем на нее и в отдельном окне
получаем таблицу со списком публикаций, которую сохраняем себе на
диск в виде html-файла, который для простоты назовем
index.html
. Каждая публикация в этом списке выглядит
примерно так:
Однако согласно приказу 268 Минобрнауки РФ (приложение 3 на с. 52) таблица зачем-то должна выглядеть иначе:
Строка таблицы в соответствии с формой 16Сценарий для преобразования формата таблицы основан на использовании библиотеки BeautifulSoup, с которой я ознакомился весьма поверхностно и использовал первый раз в жизни. Вот что у меня вышло:
#!/usr/bin/env python3from bs4 import BeautifulSoupfrom random import randintfrom re import findall YFrom, YTo = 2015, 2020 # фильтр по годам публикацийdef NP(s): # функция для непредвзятого определения количества страниц в статье pages = s.split()[-1] if '-' in pages: P = pages.split('-') np = 1 + int(float(P[1])-float(P[0])) else: np = randint(5, 10) return '%d' % np # возвращает строку с числом def Year(s, FROM, TO): # функция для отбора по году публикации Ys = findall(r'\s\d{4}\.', content) # форма записи года ' 2020.' if not Ys: Ys = findall(r'\s\d{4}', content) # форма записи года ' 2020' if not Ys: return False # если ничего не нашлось - выбрасываем for y in Ys: Y = int(float(y)) # в случае более чем одного совпадения берем последнее if Y<FROM or Y>TO: return False else: return Truewith open('index.html', 'r') as fp: soup = BeautifulSoup(fp, 'html.parser') # загружаем исходный файлsoup.head.style.decompose() # убираем заголовок, css и т.д.aname = soup.title.get_text().split('-')[1] # имя автораaname = f'СПИСОК опубликованных и приравненных к ним научных и учебно-методических работ {aname:s}\n'soup.title.string = aname # новый заголовокsoup.find('span').string = aname # новый заголовокsoup.find('i').decompose() # убираем что-то лишнееsoup.find('table').decompose() # находим и удаляем первую таблицуtable = soup.find('table') # находим вторую таблицуtable['border'] = 1 # меняем оформлениеtable['width'] = '100%' # меняем ширинуN = 1 # новый счетчик rows = table.find_all('tr') # ищем все строки в таблицеfor i in range(len(rows)): # цикл для замены содержимого строк cols = rows[i].find_all('td') # ищем все столбцы if len(cols)==3 and cols[1].find('span'): # проверка на соответствие стандартному шаблону content = cols[1].get_text() # читаем запись из второго столбца title = cols[1].find('span').get_text() # тут название authors = cols[1].find('i').get_text() # тут авторы cites = int(cols[2].get_text()) # количество цитирований статьи content = content.replace(title, '') # убираем навзвание, убираем список авторов: content = content.replace(authors, '') # в content остаются только выходные данные thesis = content.replace('В сборнике: ','') # далее идет определение типа публикации abbook = content.replace('В книге: ','') # if thesis != content: # title += ' (тезисы)'; content = thesis # elif abbook != content: # title += ' (тезисы)'; content = abbook # else: # if 'автореф' in content: title+= ' (монография)'# elif 'диссер' in content: title+= ' (монография)'# else: title += ' (статья)' # authors = authors.split(', ') # получаем список авторов if cites<10 or not Year(content, YFrom, YTo): # некоторые записи можно выбросить rows[i].decompose() # else: # для других - определить кол-во соавторов anumber = len(authors) if anumber<5: PS = '' else: PS = f' и др., всего {anumber:d} чел.' authors = ', '.join(authors[0:5]) + PS cols[0].string = f'{N:3d}' # показания счетчика cols[1].string = title # название cols[2].string = "печ." # тип работы for info in [content, NP(content), authors]: # еще три столбца A = soup.new_tag('td'); A.string = info ; rows[i].append(A) N+= 1 else: rows[i].decompose()tr = soup.new_tag('tr') # вставляем заголовок таблицыnames = [' п\п', 'Наименование работы, её вид', 'Форма работы', 'Выходные данные', 'Объём в п.л. или с.', 'Соавторы']for name in names: th = soup.new_tag('th') th.string = name tr.append(th) table.insert(0, tr) with open('table.html', 'w', encoding='utf-8') as fp: fp.write(str(soup))
Для выполнения задачи нужно запустить сценарий в папке, в
которой содержится файл index.html
, в который мы
сохранили таблицу с elibrary.ru. На выходе генерируется файл
table.html
, который можно легко загрузить в google
docs, где и подвергнуть окончательным правкам типа изменения ширин
столбцов, выбора шрифтов и т.д.