105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from playwright.sync_api import sync_playwright
|
|
import json
|
|
import requests
|
|
|
|
STATE_FILE = "medevio_storage.json"
|
|
AGENDA_URL = (
|
|
"https://my.medevio.cz/mudr-buzalkova/klinika/kalendar/agenda-dne/"
|
|
"?kalendar=144c4e12-347c-49ca-9ec0-8ca965a4470d&datum=2025-10-17"
|
|
)
|
|
GRAPHQL_URL = "https://api.medevio.cz/graphql"
|
|
|
|
|
|
def extract_agenda_rows(page):
|
|
rows = page.locator("div[data-testid='reservation-row']")
|
|
if rows.count() == 0:
|
|
raise SystemExit("❌ No rows found — check selector or login session.")
|
|
|
|
results = []
|
|
print(f"\nFound {rows.count()} rows, showing sample structure:")
|
|
for row in rows.all()[:3]:
|
|
print("-" * 80)
|
|
print(row.evaluate("el => el.outerHTML")[:500], "...\n")
|
|
|
|
# Now extract data safely
|
|
for row in rows.all():
|
|
rid = row.get_attribute("data-id") or ""
|
|
# Try to read each cell dynamically
|
|
cells = row.locator("div.MuiDataGrid-cell")
|
|
record = {"id": rid}
|
|
for c in cells.all():
|
|
field = c.get_attribute("data-field") or "unknown"
|
|
text = (c.text_content() or "").strip()
|
|
record[field] = text
|
|
results.append(record)
|
|
return results
|
|
|
|
|
|
def step1_extract_appointments():
|
|
with sync_playwright() as pw:
|
|
browser = pw.chromium.launch(headless=False, slow_mo=150)
|
|
context = browser.new_context(storage_state=STATE_FILE)
|
|
page = context.new_page()
|
|
print("🔗 Opening Medevio agenda-day page...")
|
|
page.goto(AGENDA_URL, wait_until="networkidle", timeout=90_000)
|
|
page.wait_for_selector("div[data-testid='reservation-row']", timeout=30_000)
|
|
|
|
appointments = extract_agenda_rows(page)
|
|
browser.close()
|
|
print(f"✅ Extracted {len(appointments)} appointments")
|
|
for a in appointments:
|
|
print(f"— {a.get('StartDateTime','?')} {a.get('Patient','?')}: {a.get('Reason','?')} ({a['id']})")
|
|
return appointments
|
|
|
|
|
|
def step2_fetch_detail(session_cookies, reservation_id):
|
|
headers = {
|
|
"content-type": "application/json",
|
|
"origin": "https://my.medevio.cz",
|
|
"referer": "https://my.medevio.cz/",
|
|
}
|
|
|
|
query = {
|
|
"operationName": "ReservationDetail",
|
|
"variables": {"id": reservation_id},
|
|
"query": """
|
|
query ReservationDetail($id: ID!) {
|
|
reservation(id: $id) {
|
|
id
|
|
reason
|
|
startDateTime
|
|
endDateTime
|
|
status
|
|
note
|
|
patient { id name age }
|
|
doctor { id name }
|
|
location { name }
|
|
}
|
|
}
|
|
""",
|
|
}
|
|
|
|
print(f"\n📡 Fetching GraphQL detail for {reservation_id}...")
|
|
response = requests.post(GRAPHQL_URL, headers=headers, cookies=session_cookies, data=json.dumps(query))
|
|
print("Status:", response.status_code)
|
|
print(json.dumps(response.json(), indent=2, ensure_ascii=False))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
appointments = step1_extract_appointments()
|
|
if not appointments:
|
|
raise SystemExit("No appointments found.")
|
|
|
|
# Use first appointment for detail fetch
|
|
reservation_id = appointments[0]["id"]
|
|
|
|
# Load session cookies from storage
|
|
with open(STATE_FILE, "r", encoding="utf-8") as f:
|
|
state = json.load(f)
|
|
cookies = {c["name"]: c["value"] for c in state.get("cookies", []) if "medevio" in c["domain"]}
|
|
|
|
step2_fetch_detail(cookies, reservation_id)
|