Небольшой пост о том, как собрать в единый pdf все записи о сданных анализах в поликлинике из электронной медицинской карты. Данные располагаются на сайте (https://lk.emias.mos.ru/medical-records), однако пользоваться ими неудобно, так как на сайте все свалено в несколько pdf куч. И, чтобы посмотреть, все позиции по анализам, сданным, например, в один день, необходимо заходить в каждую из этих куч и смотреть только эту одну позицию. Итого можно посмотреть до 15 pdf с анализами, сданных в один день. А уж если хочется за несколько дней посмотреть результаты анализов, умножай на n и затем вручную сравнивай!
В качестве опции также будет осуществлен вывод табличных данных из pdf в excel.
Выглядит все это примерно следующим образом:
Нажимая на стрелочку вниз, предлагается скачивать файлы pdf и далее их изучать вручную.
За два года может накопиться до 125 файлов и в них легко запутаться, так как при скачивании они принимают одинаковые имена, а об их дате можно узнать, лишь открыв их.
Что будет делать программа ?
Программа будет «заходить» на сайт медкарты, позволяя пользователю ввести только код из смс (необходимое требование при регистрации на сайте), находить раздел с анализами, «проваливаться» туда, скачивать все pdf. Далее, исходя из дат сдачи анализов, программа разложит их по папкам с соответствующей датой, склеит в каждой папке все файлы в один pdf.
В итоговом pdf файле программа выделит цветом, если есть отклонение:
Во второй части мини-проекта будет осуществлен вывод всех данных из всех pdf с анализами в единую excel таблицу с использованием несколько различных подходов.
Приступаем.
Импорты библиотек:
import webbrowser,time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
import shutil
import PyPDF2, os
import fitz
*При установке модуля fitz, может потребоваться модуль PyMuPDF. При установке последнего (pip install PyMuPDF) можно столкнуться с ошибкой «error: Microsoft Visual C++ 14.0 is required. Get it with „Microsoft Visual...“ Чтобы ее обойти можно попробовать установить модуль следующим образом: „pip install --only-binary :all: PyMuPDF“.
Заходить на сайт будем с помощью модуля selenium и браузера chrome. Поэтому все настройки для них:
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
# options.add_argument("--headless")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
browser = webdriver.Chrome(options=options)
#browser = webdriver.Firefox(options=options)
browser.get ('https://lk.emias.mos.ru/medical-records')
time.sleep (5)
*Для запуска браузера может потребоваться chromedriver. Если web-страница не открывается программой и вылетает с ошибкой, в которой присутствует chromedriver — обновите chromedriver, скачайте версию для своего браузера.
Далее идет блок авторизации на сайте медкарты, проходящий через сайт mos.ru.
Программа сама вбивает логин и пароль в нужные поля (эти поля необходимо предварительно заполнить в программе), нажимает кнопку „Войти“. Однако, так как требуется еще и ввести код из смс на странице, пользователю необходимо ввести его вручную на сайте, когда появится соответствующее сообщение. В оболочке, в которой работает программа python, также необходимо нажать любую кнопку, чтобы программа продолжила работу:
act = browser.find_element_by_id('login')
for i in 'login@yandex.ru':
act.send_keys(i)
time.sleep (0.1)
act = browser.find_element_by_id('password')
for i in 'password':
act.send_keys(i)
time.sleep (0.1)
act = browser.find_element_by_id('bind').click()
x=input('Введите код sms на странице и нажмите любую кнопку здесь')
Переход на сайте в раздел с анализами и переход в директорию на диске, куда будет производиться сохранение:
act = browser.find_element_by_css_selector('#analyzes_card_open_button > div > span')
act.click()
time.sleep(3)
act = browser.find_element_by_css_selector('#analyzes_card_all > div > span')
act.click()
time.sleep(3)
cwd = os.path.join(os.path.expandvars("%userprofile%"),"Downloads")
os.chdir(cwd)
Основной цикл программы
Теперь программа будет брать дату на сайте перед каждой записью анализа и создавать
одноименную папку на диске. Скачивать без подтверждения pdf с сайта, а так как директория скачивания едина для всех файлов (задана при создании browser), то еще и перемещать каждый pdf в целевую директорию с помощью shututil.
#переходим в папку для скачивания и скачиваем, создавая папки по датам
x=0
try:
while True:
text=browser.find_element_by_xpath('/html/body/div[1]/div[1]/div[3]/div[2]/div/div[2]/div[1]/div[1]/div[2]/div[3]/div/div[3]/div[2]/div/div['+str(x+1)+']/span').text
if not os.path.exists(text):
os.makedirs(text)
act=browser.find_element_by_css_selector('#analyzes_list_download-'+str(x)+' > div > svg')
act.click()
time.sleep(2)
for root, dirs, files in os.walk("."):
for file in files:
if file.endswith('pdf'):
try:
shutil.move(file, text) #перенос файла в целевую директорию
except:
pass
x+=1
except:
pass
В результате должны появиться папки с датами сдачи анализов, а внутри папок — все анализы, сданные в эту дату:
Вспомогательные функции
Создадим функцию, которая склеит все pdf в один файл.
#работаем с текстом в файлах
def join_pdfs():
pdfFiles = []
for filename in os.listdir('.'):
if filename.endswith('.pdf'):
pdfFiles.append(filename)
pdfFiles.sort()
pdfWriter = PyPDF2.PdfFileWriter()
# Loop through all the PDF files.
for filename in pdfFiles:
pdfFileObj = open(filename, 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
# Loop through all the pages and add them.
for pageNum in range(0, pdfReader.numPages):
pageObj = pdfReader.getPage(pageNum)
pdfWriter.addPage(pageObj)
# Save the resulting PDF to a file.
pdfOutput = open('all.pdf', 'wb')
pdfWriter.write(pdfOutput)
pdfOutput.close()
А также функцию, которая подсветит желтым маркером результаты анализа, если есть отклонения. Здесь просто поиск по тексту искомой фразы.
def highlight():
#помечаем отклонения в файле all.pdf желтым цветом и сохраняем как highlighted_text.pdf
with fitz.open('all.pdf') as doc:
for page in doc:
areas = page.searchFor("отклонение от")
page.addHighlightAnnot(areas)
doc.save("highlighted_text.pdf")
Теперь применим созданные функции ко всем папкам с анализами.
for root, dirs, files in os.walk("."):
for i in dirs:
os.chdir(i)
join_pdfs()
highlight()
os.chdir('..')
В результате в каждой папке создается файл all.pdf и файл highlighted_text.pdf, в которых собраны результаты, а во втором файле еще и подсвечены отклонения.
Сформируем единую таблицу excel, собрав данные из таблиц pdf
Для этих целей воспользуемся двумя сторонними пакетами и посмотрим, насколько корректно они обработают таблицы в pdf файлах с анализами.
Первый пакет — camelot —
pip install camelot-py[cv]
Для работы с ним также придется установить стороннее приложение ghostscript и добавить его в PATH (например, C:\gostscript\gs9.55.0\bin).
Сама программа выглядит так:
import os
import shutil
import pandas as pd
df1 = pd.DataFrame()
for root, dirs, files in os.walk("."):
for i in dirs:
os.chdir(i)
date_my = {'Тест': i} #добавили дату в датафрейм
df1=df1.append(date_my,ignore_index=True)
for root, dirs, files in os.walk("."):
for file in files:
if file.endswith('.pdf'):
print(file)
tables = camelot.read_pdf(file)
print("Total tables extracted:", tables.n)
for n in range(len(tables)):
df1=df1.append(tables[n].df[1:],ignore_index=True)#добавили датафрейм
os.chdir('..')
df1.to_excel('out1.xlsx',header=False, index=False)
Camelot создает датафреймы, которые понимает pandas. В данном случае мы первоначально создали свой датафрейм, далее добавили в него строку с датой сдачи анализов в целом и, далее, в цикле добавили все извлеченные таблицы из всех pdf.
По непонятным причинам camelot обрабатывает не все pdf c табличными данными и из некоторых файлов не извлекает таблицы, несмотря на то, что структурно файлы схожи между собой:
Тем не менее, результат для извлеченных данных неплохой:
Теперь посмотрим на альтернативный пакет — tabula.
pip install tabula-py
Он также требует установки дополнительного ПО, в данном случае java (jre). Путь к последней, также необходимо добавить в PATH (Например, C:\Program Files (x86)\Java\jre1.8.0_221\bin).
Текст программы схож с предыдущей:
import tabula
#https://www.thepythoncode.com/article/extract-pdf-tables-in-python-camelot
#tabula-py
#необходима java (jre), путь к которой доваить в PATH - C:\Program Files (x86)\Java\jre1.8.0_221\bin
#выводит итоговый результат из всех директорий в out2.xlsx
import csv,os
import shutil
import pandas as pd
df1 = pd.DataFrame()
for root, dirs, files in os.walk("."):
for i in dirs:
#print(i)
#print(os.getcwd())
os.chdir(i)
date_my = {'Тест': i} #добавили дату в датафрейм
df1=df1.append(date_my,ignore_index=True)
for root, dirs, files in os.walk("."):
for file in files:
if file.endswith('.pdf'):
if file=='Определение ГГТ-γ-глютамилтрансферазы.pdf':
os.rename(file, 'Определение ГГТ-глютамилтрансферазы.pdf')
file='Определение ГГТ-глютамилтрансферазы.pdf'
print(file)
tables = tabula.read_pdf(file, pages="all")
df1=df1.append(tables,ignore_index=True)#добавили датафрейм
os.chdir('..')
df1.to_excel('out2.xlsx',header=False, index=False)
Обработка pdf идет также, через преобразование таблиц в датафреймы.
Tabula обработала в итоге все файлы pdf, даже те, что не смог camelot. Однако в excel таблицы
отобразились не идеально:
На этом все, теперь можно наслаждаться результатами анализов, созерцая все вместе.
Надеюсь, программы окажутся полезными. Хотя бы до тех пор, пока в личном кабинете электронной медицинской карты не появится схожий функционал.
Скачать программы — здесь.
Комментарии (2)
PTM
22.11.2021 18:09«Вашу карточку сдали в архив. Ждите 2-3 часа пока сделаем запрос. Ну и что, что вы записались к ЛОР 2 недели назад, за талончиком вы только что подошли»
yarglor
*.mos.ru? Надо бы где-то в тексте статьи указать, что речь идёт о Москве-онли. А то ведь не все ещё в Москву переехали.