r
This commit is contained in:
42
Medevio3.py
42
Medevio3.py
@@ -1,42 +0,0 @@
|
|||||||
# save_patient_detail_page.py
|
|
||||||
from pathlib import Path
|
|
||||||
from playwright.sync_api import sync_playwright
|
|
||||||
|
|
||||||
STATE_FILE = r"/medevio_storage.json"
|
|
||||||
BASE_URL = "https://my.medevio.cz/mudr-buzalkova/klinika/pacienti"
|
|
||||||
PATIENT_ID = "fcb2414b-067b-4ca2-91b2-6c36a86d4cbb" # <-- any valid patient UUID
|
|
||||||
|
|
||||||
def main():
|
|
||||||
out_dir = Path(f"capture_patient_{PATIENT_ID}")
|
|
||||||
out_dir.mkdir(exist_ok=True)
|
|
||||||
|
|
||||||
html_path = out_dir / "detail.html"
|
|
||||||
screenshot_path = out_dir / "detail.png"
|
|
||||||
|
|
||||||
with sync_playwright() as p:
|
|
||||||
browser = p.chromium.launch(headless=True) # set False if you want to watch
|
|
||||||
context = browser.new_context(storage_state=STATE_FILE)
|
|
||||||
page = context.new_page()
|
|
||||||
|
|
||||||
# Open the detail directly
|
|
||||||
target_url = f"{BASE_URL}?pacient={PATIENT_ID}"
|
|
||||||
page.goto(target_url, wait_until="domcontentloaded")
|
|
||||||
|
|
||||||
# Wait a bit for the detail drawer/dialog to render
|
|
||||||
try:
|
|
||||||
page.wait_for_selector("[role='dialog'], div.MuiDrawer-paper, div[aria-modal='true']", timeout=10000)
|
|
||||||
except:
|
|
||||||
print("Warning: did not detect a detail panel quickly")
|
|
||||||
|
|
||||||
# Save raw HTML and screenshot
|
|
||||||
html_path.write_text(page.content(), encoding="utf-8")
|
|
||||||
page.screenshot(path=str(screenshot_path), full_page=True)
|
|
||||||
|
|
||||||
browser.close()
|
|
||||||
|
|
||||||
print("Saved:")
|
|
||||||
print(" -", html_path.resolve())
|
|
||||||
print(" -", screenshot_path.resolve())
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
111
Medevio3CapturePatients.py
Normal file
111
Medevio3CapturePatients.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
import mysql.connector
|
||||||
|
import time
|
||||||
|
|
||||||
|
MYSQL_CFG = dict(
|
||||||
|
host="192.168.1.76",
|
||||||
|
port=3307,
|
||||||
|
user="root",
|
||||||
|
password="Vlado9674+",
|
||||||
|
database="medevio",
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- load 3 patients from DB ---
|
||||||
|
conn = mysql.connector.connect(**MYSQL_CFG)
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute("""
|
||||||
|
SELECT rid, prijmeni, jmeno, rc
|
||||||
|
FROM patients_extracted
|
||||||
|
WHERE prijmeni IS NOT NULL
|
||||||
|
ORDER BY prijmeni ASC
|
||||||
|
LIMIT 3
|
||||||
|
""")
|
||||||
|
rows = cur.fetchall()
|
||||||
|
if not rows:
|
||||||
|
raise RuntimeError("No entries found in patients_extracted")
|
||||||
|
|
||||||
|
STATE_FILE = r"medevio_storage.json"
|
||||||
|
BASE_URL = "https://my.medevio.cz/mudr-buzalkova/klinika/pacienti"
|
||||||
|
|
||||||
|
NOT_FOUND_SEL = "div[role='alert']:has-text('Pacient nebyl nalezen'), div:has-text('Pacient nebyl nalezen')"
|
||||||
|
DIALOG_SEL = "[role='dialog'], div.MuiDrawer-paper, div[aria-modal='true']"
|
||||||
|
|
||||||
|
def close_dialog_if_open(page):
|
||||||
|
dlg = page.locator(DIALOG_SEL)
|
||||||
|
try:
|
||||||
|
if dlg.count():
|
||||||
|
# Try a close button; if not, press Escape
|
||||||
|
try:
|
||||||
|
dlg.locator("button:has-text('Zavřít'), [aria-label='Zavřít'], [aria-label='Close'], [data-testid='CloseIcon']").first.click(timeout=1000)
|
||||||
|
except:
|
||||||
|
page.keyboard.press("Escape")
|
||||||
|
page.wait_for_selector(DIALOG_SEL, state="detached", timeout=1500)
|
||||||
|
except:
|
||||||
|
pass # best-effort close
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=False)
|
||||||
|
try:
|
||||||
|
context = browser.new_context(storage_state=STATE_FILE)
|
||||||
|
page = context.new_page()
|
||||||
|
|
||||||
|
for rid, surname, name, rc in rows:
|
||||||
|
# 0) close any previous dialog to avoid stale matches
|
||||||
|
close_dialog_if_open(page)
|
||||||
|
|
||||||
|
target_url = f"{BASE_URL}?pacient={rid}"
|
||||||
|
page.goto(target_url, wait_until="domcontentloaded")
|
||||||
|
page.wait_for_load_state("networkidle")
|
||||||
|
|
||||||
|
# 1) Not-found toast?
|
||||||
|
try:
|
||||||
|
page.wait_for_selector(NOT_FOUND_SEL, timeout=3000)
|
||||||
|
print(f"{surname} {name} {rc} – ⚠️ pacient s RID {rid} nebyl nalezen, přeskočeno")
|
||||||
|
# (optional) set mamedevioucet=NULL for this rid here
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 2) Detail panel
|
||||||
|
try:
|
||||||
|
page.wait_for_selector(DIALOG_SEL, timeout=6000)
|
||||||
|
except:
|
||||||
|
print(f"⚠️ {surname} {name} {rc}: detailový panel se nenačetl, přeskočeno")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 3) Verify dialog belongs to current patient (avoid stale dialog)
|
||||||
|
detail = page.locator(DIALOG_SEL).first
|
||||||
|
detail_text = detail.inner_text()
|
||||||
|
|
||||||
|
if (surname not in detail_text) and (rc not in detail_text):
|
||||||
|
# Still looks wrong; give UI a moment and re-check once
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
detail_text = detail.inner_text()
|
||||||
|
if (surname not in detail_text) and (rc not in detail_text):
|
||||||
|
print(f"⚠️ {surname} {name} {rc}: detail neodpovídá (stará karta?), přeskočeno")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 4) Check Medevio account text
|
||||||
|
if "zatím nemá Medevio účet" in detail_text:
|
||||||
|
has_account = 0
|
||||||
|
print(f"{surname} {name} {rc} – ❌ zatím nemá Medevio účet")
|
||||||
|
else:
|
||||||
|
has_account = 1
|
||||||
|
print(f"{surname} {name} {rc} – ✅ má Medevio účet")
|
||||||
|
|
||||||
|
# Update DB by RID (or swap to rc if you prefer)
|
||||||
|
with conn.cursor() as c:
|
||||||
|
c.execute(
|
||||||
|
"UPDATE patients_extracted SET mamedevioucet = %s WHERE rid = %s",
|
||||||
|
(has_account, rid),
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
time.sleep(0.5) # gentle pacing
|
||||||
|
|
||||||
|
finally:
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
import mysql.connector
|
import mysql.connector
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
# ---------- CONFIG ----------
|
|
||||||
# MySQL connection settings (fill in)
|
|
||||||
MYSQL_CFG = dict(
|
MYSQL_CFG = dict(
|
||||||
host="192.168.1.76",
|
host="192.168.1.76",
|
||||||
port=3307,
|
port=3307,
|
||||||
@@ -13,30 +11,100 @@ MYSQL_CFG = dict(
|
|||||||
database="medevio",
|
database="medevio",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#Helper functions
|
||||||
|
def is_valid_rc(rc: str) -> bool:
|
||||||
|
"""
|
||||||
|
Very basic RC check:
|
||||||
|
– remove any slash
|
||||||
|
– must be 9 or 10 digits
|
||||||
|
"""
|
||||||
|
rc_clean = rc.replace("/", "")
|
||||||
|
return bool(re.fullmatch(r"\d{9,10}", rc_clean))
|
||||||
|
|
||||||
conn = mysql.connector.connect(**MYSQL_CFG)
|
conn = mysql.connector.connect(**MYSQL_CFG)
|
||||||
cur=conn.cursor()
|
|
||||||
cur.execute("select html from kartoteka_html where 'fetched-at'=(SELECT MAX('fetched-at') FROM kartoteka_html)")
|
|
||||||
html=cur.fetchone()
|
|
||||||
html=html[0]
|
|
||||||
|
|
||||||
|
# --- get latest HTML (single-row result) ---
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute("""
|
||||||
|
SELECT html
|
||||||
|
FROM kartoteka_html
|
||||||
|
where round=3
|
||||||
|
ORDER BY `fetched-at` DESC
|
||||||
|
""")
|
||||||
|
rows = cur.fetchall()
|
||||||
|
if not rows:
|
||||||
|
raise RuntimeError("No HTML found in kartoteka_html")
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
|
||||||
|
html = row[0]
|
||||||
|
|
||||||
# html is the string containing the entire web page
|
|
||||||
soup = BeautifulSoup(html, "html.parser")
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
|
|
||||||
# Find every <button> that has that specific class sequence
|
records = []
|
||||||
# (space-separated class names → match as a set)
|
for row in soup.find_all("div", attrs={"role": "row", "data-id": True}):
|
||||||
buttons = soup.find_all(
|
data_id = row["data-id"]
|
||||||
"button",
|
|
||||||
class_="MuiTypography-root MuiTypography-body2 "
|
|
||||||
"MuiLink-root MuiLink-underlineAlways "
|
|
||||||
"MuiLink-button css-xf7pf8"
|
|
||||||
)
|
|
||||||
names = []
|
|
||||||
for btn in buttons:
|
|
||||||
text = btn.get_text(strip=True)
|
|
||||||
print(text)
|
|
||||||
names.append(text)
|
|
||||||
|
|
||||||
print(names)
|
# full name -> surname + rest
|
||||||
# names = [btn.get_text(strip=True) for btn in buttons]
|
name_btn = row.find("button", class_="MuiTypography-root")
|
||||||
print(names)
|
fullname = name_btn.get_text(strip=True) if name_btn else ""
|
||||||
|
parts = fullname.split()
|
||||||
|
surname = parts[0] if parts else ""
|
||||||
|
name = " ".join(parts[1:]) if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
# RC
|
||||||
|
id_cell = row.find("div", attrs={"data-field": "IdentificationNumber"})
|
||||||
|
rc = (id_cell.get("title", "") if id_cell else "")
|
||||||
|
rc = rc.replace("/", "").replace("\\", "")
|
||||||
|
|
||||||
|
# Phone
|
||||||
|
ph_cell = row.find("div", attrs={"data-field": "Phone"})
|
||||||
|
raw_phone = ph_cell.get("title", "") if ph_cell else ""
|
||||||
|
raw_phone = raw_phone.replace("\u00A0", " ") # NBSP -> space
|
||||||
|
phone = re.sub(r"[^\d+]", "", raw_phone) # keep + and digits
|
||||||
|
|
||||||
|
# Insurance
|
||||||
|
ins_cell = row.find("div", attrs={"data-field": "InsuranceCompany"})
|
||||||
|
poj = ins_cell.get("title", "") if ins_cell else ""
|
||||||
|
|
||||||
|
# Skip rows with no name or no RC or not valid TC
|
||||||
|
if not fullname or not rc:
|
||||||
|
continue
|
||||||
|
if not is_valid_rc(rc):
|
||||||
|
continue
|
||||||
|
|
||||||
|
records.append((data_id, fullname, rc, phone, poj))
|
||||||
|
|
||||||
|
# --- per-patient lookup: use a fresh cursor each time (or buffered=True) ---
|
||||||
|
with conn.cursor(buffered=True) as cur2:
|
||||||
|
cur2.execute(
|
||||||
|
"""
|
||||||
|
SELECT *
|
||||||
|
FROM patients_extracted
|
||||||
|
WHERE rc=%s
|
||||||
|
""",
|
||||||
|
(rc,),
|
||||||
|
)
|
||||||
|
rows = cur2.fetchall()
|
||||||
|
|
||||||
|
# print(surname, name, rc, len(rows))
|
||||||
|
|
||||||
|
if len(rows) > 1:
|
||||||
|
print(f"Pacient {surname} {name} {rc} je v medeviu {len(rows)}x")
|
||||||
|
time.sleep(1)
|
||||||
|
if len(rows)==0:
|
||||||
|
print(f"Pacient {surname} {name} {rc} je v medeviu {len(rows)}x")
|
||||||
|
time.sleep(1)
|
||||||
|
if len(rows)==1 and rows[0][0]!=data_id:
|
||||||
|
print(f"Pacient {surname} {name} {rc} má v medeviu jiný id, v db je {rows[0][0]} and nyní je {data_id}")
|
||||||
|
time.sleep(.1)
|
||||||
|
|
||||||
|
if len(rows) == 1:
|
||||||
|
cur2.execute("""
|
||||||
|
Update patients_extracted set rid=%s where rc=%s""",(data_id,rc))
|
||||||
|
conn.commit()
|
||||||
|
# preview
|
||||||
|
# for r in records[:10]:
|
||||||
|
# print(f"ID: {r[0]} Name: {r[1]} RC: {r[2]} Phone: {r[3]} Pojistovna: {r[4]}")
|
||||||
|
#
|
||||||
|
# print("Total patients:", len(records))
|
||||||
|
|||||||
0
Medevio6 ReadPatientCards.py
Normal file
0
Medevio6 ReadPatientCards.py
Normal file
File diff suppressed because one or more lines are too long
BIN
capture_patient_0117c85c-630d-44c4-a5ca-dd9f3b28e25e/detail.png
Normal file
BIN
capture_patient_0117c85c-630d-44c4-a5ca-dd9f3b28e25e/detail.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user