notebook
This commit is contained in:
80
8 medevio read calendar.py
Normal file
80
8 medevio read calendar.py
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Open the Medevio daily agenda calendar,
|
||||||
|
inspect the rendered HTML, and probe JS memory
|
||||||
|
to see what data is exposed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
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 agenda-day calendar...")
|
||||||
|
page.goto(AGENDA_URL, wait_until="networkidle", timeout=90_000)
|
||||||
|
|
||||||
|
# -------- Check login --------
|
||||||
|
body = (page.text_content("body") or "").lower()
|
||||||
|
if any(x in body for x in ["přihlášení", "přihlásit", "sign in", "login"]):
|
||||||
|
raise SystemExit("❌ Not logged in – refresh medevio_storage.json.")
|
||||||
|
|
||||||
|
# -------- Wait for appointments to render --------
|
||||||
|
page.wait_for_timeout(4000)
|
||||||
|
|
||||||
|
# -------- Dump a few appointment blocks --------
|
||||||
|
blocks = page.locator("div.rbc-event-inner-content, div[data-testid='Reservation']").evaluate_all(
|
||||||
|
"(els) => els.map(e => e.outerHTML)"
|
||||||
|
)
|
||||||
|
print(f"\n✅ Found {len(blocks)} appointment blocks. Showing first 3:\n")
|
||||||
|
for snippet in blocks[:3]:
|
||||||
|
print(snippet)
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
# -------- Explore window memory --------
|
||||||
|
print("\n🔍 Inspecting global JS variables...")
|
||||||
|
keys = page.evaluate("Object.keys(window)")
|
||||||
|
interesting = [k for k in keys if any(w in k.lower() for w in ["mede", "cal", "react", "state", "reserv"])]
|
||||||
|
print("Interesting keys:", interesting[:20])
|
||||||
|
|
||||||
|
for candidate in [
|
||||||
|
"window.__INITIAL_STATE__",
|
||||||
|
"window.__INITIAL_DATA__",
|
||||||
|
"window.__REACT_DEVTOOLS_GLOBAL_HOOK__",
|
||||||
|
"window.medevioCalendar",
|
||||||
|
"window.calendarStore",
|
||||||
|
"window.reduxStore",
|
||||||
|
"window.reactProps",
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
data = page.evaluate(f"JSON.stringify({candidate}, null, 2)")
|
||||||
|
if data and len(data) > 200:
|
||||||
|
print(f"\n===== {candidate} =====\n{data[:1000]}...\n")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# -------- Optionally: listen for network requests while you click --------
|
||||||
|
def log_request(req):
|
||||||
|
url = req.url
|
||||||
|
if any(x in url for x in ["pozadavek", "request", "api"]):
|
||||||
|
print("📡", url)
|
||||||
|
|
||||||
|
page.on("request", log_request)
|
||||||
|
print("\n👉 Now click manually on a few agenda items to open their detail cards.")
|
||||||
|
print(" Any backend calls will appear below.\n")
|
||||||
|
|
||||||
|
page.wait_for_timeout(40000) # give yourself ~40s to click around
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
104
81 Read agenda and give 1.py
Normal file
104
81 Read agenda and give 1.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/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)
|
||||||
44
82 test.py
Normal file
44
82 test.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import json, requests
|
||||||
|
|
||||||
|
GRAPHQL_URL = "https://api.medevio.cz/graphql"
|
||||||
|
|
||||||
|
FULL_INTROSPECTION_QUERY = """
|
||||||
|
query IntrospectionQuery {
|
||||||
|
__schema {
|
||||||
|
queryType { name }
|
||||||
|
mutationType { name }
|
||||||
|
subscriptionType { name }
|
||||||
|
types {
|
||||||
|
...FullType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment FullType on __Type {
|
||||||
|
kind
|
||||||
|
name
|
||||||
|
fields(includeDeprecated: true) {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
"origin": "https://my.medevio.cz",
|
||||||
|
"referer": "https://my.medevio.cz/",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load cookies from storage
|
||||||
|
state = json.load(open("medevio_storage.json", encoding="utf-8"))
|
||||||
|
cookies = {c["name"]: c["value"] for c in state["cookies"] if "medevio" in c["domain"]}
|
||||||
|
|
||||||
|
payload = {"operationName": "IntrospectionQuery", "query": FULL_INTROSPECTION_QUERY}
|
||||||
|
|
||||||
|
r = requests.post(GRAPHQL_URL, headers=headers, cookies=cookies, data=json.dumps(payload))
|
||||||
|
print("Status:", r.status_code)
|
||||||
|
try:
|
||||||
|
data = r.json()
|
||||||
|
print(json.dumps(data, indent=2, ensure_ascii=False)[:2000])
|
||||||
|
except Exception as e:
|
||||||
|
print("Could not decode response:", e)
|
||||||
|
print(r.text)
|
||||||
41
83_capture_graphql.py
Normal file
41
83_capture_graphql.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
import json, os, time
|
||||||
|
|
||||||
|
STATE_FILE = "medevio_storage.json"
|
||||||
|
GRAPHQL_LOG = f"graphql_capture_{int(time.time())}.jsonl"
|
||||||
|
|
||||||
|
with sync_playwright() as pw:
|
||||||
|
browser = pw.chromium.launch(headless=False, slow_mo=200)
|
||||||
|
context = browser.new_context(storage_state=STATE_FILE)
|
||||||
|
page = context.new_page()
|
||||||
|
|
||||||
|
def log_graphql(req):
|
||||||
|
if "graphql" in req.url and req.method == "POST":
|
||||||
|
try:
|
||||||
|
body = req.post_data or ""
|
||||||
|
data = json.loads(body)
|
||||||
|
with open(GRAPHQL_LOG, "a", encoding="utf-8") as f:
|
||||||
|
f.write(json.dumps(data, ensure_ascii=False) + "\n")
|
||||||
|
print(f"📡 {data.get('operationName')} saved")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
page.on("request", log_graphql)
|
||||||
|
|
||||||
|
print("🔗 Opening Medevio main page...")
|
||||||
|
page.goto("https://my.medevio.cz/mudr-buzalkova/klinika/kalendar/agenda-dne/"
|
||||||
|
"?kalendar=144c4e12-347c-49ca-9ec0-8ca965a4470d", wait_until="networkidle")
|
||||||
|
|
||||||
|
print("\n👉 Click various items in Medevio (calendar, reservations, requests, etc.).")
|
||||||
|
print(" Every GraphQL call will be saved to", GRAPHQL_LOG)
|
||||||
|
print(" Press Ctrl+C or close the browser when done.\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
browser.close()
|
||||||
|
print(f"\n✅ Finished — GraphQL calls saved to {GRAPHQL_LOG}")
|
||||||
100
84 test.py
Normal file
100
84 test.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Query Medevio for the full agenda of 17 Oct 2025 and print raw API response.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
GRAPHQL_URL = "https://api.medevio.cz/graphql"
|
||||||
|
|
||||||
|
CALENDAR_ID = "144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
CLINIC_SLUG = "mudr-buzalkova"
|
||||||
|
|
||||||
|
def load_gateway_token(storage_path="medevio_storage.json"):
|
||||||
|
"""Return Medevio gateway-access-token from saved Playwright storage."""
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path(storage_path)
|
||||||
|
if not path.exists():
|
||||||
|
raise SystemExit(f"❌ Storage file not found: {path}")
|
||||||
|
|
||||||
|
with path.open("r", encoding="utf-8") as f:
|
||||||
|
state = json.load(f)
|
||||||
|
|
||||||
|
token = next(
|
||||||
|
(c["value"] for c in state["cookies"]
|
||||||
|
if c["name"] == "gateway-access-token"), None
|
||||||
|
)
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
raise SystemExit("❌ gateway-access-token not found in storage file.")
|
||||||
|
|
||||||
|
return token
|
||||||
|
|
||||||
|
gateway_token = load_gateway_token()
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
"origin": "https://my.medevio.cz",
|
||||||
|
"referer": "https://my.medevio.cz/",
|
||||||
|
"authorization": f"Bearer {gateway_token}",
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"operationName": "ClinicAgenda_ListClinicReservations",
|
||||||
|
"variables": {
|
||||||
|
"calendarIds": [CALENDAR_ID],
|
||||||
|
"clinicSlug": CLINIC_SLUG,
|
||||||
|
"since": "2025-10-16T22:00:00.000Z",
|
||||||
|
"until": "2025-10-17T21:59:59.999Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": False,
|
||||||
|
},
|
||||||
|
"query": """query ClinicAgenda_ListClinicReservations(
|
||||||
|
$calendarIds: [UUID!],
|
||||||
|
$clinicSlug: String!,
|
||||||
|
$locale: Locale!,
|
||||||
|
$since: DateTime!,
|
||||||
|
$until: DateTime!,
|
||||||
|
$emptyCalendarIds: Boolean!
|
||||||
|
) {
|
||||||
|
reservations: listClinicReservations(
|
||||||
|
clinicSlug: $clinicSlug,
|
||||||
|
calendarIds: $calendarIds,
|
||||||
|
since: $since,
|
||||||
|
until: $until
|
||||||
|
) @skip(if: $emptyCalendarIds) {
|
||||||
|
id
|
||||||
|
start
|
||||||
|
end
|
||||||
|
note
|
||||||
|
done
|
||||||
|
color
|
||||||
|
request {
|
||||||
|
id
|
||||||
|
displayTitle(locale: $locale)
|
||||||
|
extendedPatient {
|
||||||
|
name
|
||||||
|
surname
|
||||||
|
dob
|
||||||
|
insuranceCompanyObject { shortName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}""",
|
||||||
|
}
|
||||||
|
|
||||||
|
print("📡 Querying Medevio API for agenda of 17 Oct 2025...")
|
||||||
|
r = requests.post(GRAPHQL_URL, headers=headers, data=json.dumps(payload))
|
||||||
|
print("Status:", r.status_code)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = r.json()
|
||||||
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
except Exception as e:
|
||||||
|
print("❌ Could not parse JSON:", e)
|
||||||
|
print(r.text)
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"cookies": [{"name": "gateway-access-token", "value": "siiQdoYzEwMy3QUPQtHkUoJr6KGkdMJWX2xP47Bwr1SH8Tin4sROlJV/KpBlKl/bVViG9aktQOXmcmcY", "domain": "my.medevio.cz", "path": "/", "expires": 1761076304, "httpOnly": false, "secure": false, "sameSite": "Lax"}, {"name": "aws-waf-token", "value": "d1c38c75-3a6a-458d-b446-67df055372e9:CgoAliiKsQdKAAAA:9TJuIJZ01Qb0+kOyO8Ts9H7zh4kHnIldQcWNkJRmwzQJNDwQ/J/Jpw67r76cKM9jDfFXRYYbJtBPb/QJ7kbMcWckSZKB0fL2TKJhib9xLarYjvm2Eu+wTll08nisMUOa7LaroeMJ7nnE0m8jCRmoCz3c2+EWMjRHRJsJ9e+fDE4uXfYrALyBZryvX+7048AY17JW73UuNK21bus3ODXjOviZCFBh3OCHwC9IX0ClW4xrBCzN5uqtXT9OGm2aJKSWGs3IlZQ=", "domain": ".my.medevio.cz", "path": "/", "expires": 1758829907, "httpOnly": false, "secure": true, "sameSite": "Lax"}], "origins": [{"origin": "https://my.medevio.cz", "localStorage": [{"name": "awswaf_token_refresh_timestamp", "value": "1758484300098"}, {"name": "awswaf_session_storage", "value": "d1c38c75-3a6a-458d-b446-67df055372e9:CgoAliiKsQhKAAAA:FW9mIZy/Za1OyAHnRHgnpQBZWQz3rrOPnh2MOZ/83oVVADSY5xWChgKzF9ZZAg0Vd19PnOaE8AlAsw1KHD6xlmrBvlAlL/qzqxgWO8fmJmtrO3ZZbUrMyaqlQRLab0G85japL6jJKHQWcMtdj1lKnE17RqnoeVHX6FJvK6kvhIeVLp88j1TNTBkMcMJShnXMLn4F/l/GC91TcgnE1k4G6VWAbLzOqcRcxjWLe/boFkAWRiF5EhqO6By635TryNmgGiXQT5kXiGsHzxhUg17xewy+IHe6prGaq8UIpMXD7LMRFjlc8+RbQJAUwieztpmc1urc+GCqb3O9fGBLWiqekHPS+95bmr9x0lLAJOVNma11waGApkTusHADPWJ4c+eBfw+5OgGBQesBCtW/HG3Obj6Ou0dfTiUKG2XmXHpEsN6Xc2w3nTmyDzioSSMhfFmBCv9AJ8G9iVOyRIfknsLH8Wl8zgFkaJI7d5awiC3W/a1BV0HPONLQywrVq5l5TG3QpZs3GbQXUs1gHZjdI8hCoLeFJPSrxis3CwezKCs4qexfkyDRvzuqGS8Qy7s6hL/JqU3RiprpzzXOWNLVcDC+TpYArmH35yET1neb7k/iinozEjjW7Kp3cB4XXJpvR0dK+5NTva7+lw5HovGPs9UNj08a1LrfvdtzisI09vaSTVnYPiaWi3j4bUc+7FXEU2qfKoA51ZabIDkFwdbLkX6156KQls4fDEnj/1+/hWkCkBa/LfRg/KU9iDex96HxZi95pDqdVSe5Rgyt6PGDqCXXw8/tgw7v8qYMOr9zAQRqQc3zMHZvC4PqVVAfuXwy3mCJ9KY1gH1ZkofuR77TDbtn//vL2XAbSm1WhVOP8MF12O6C6q9sCx6nuypwCOY7v/Ix1JqgeZIWfSi0KkQ99EzRyFyTbcJO4A=="}, {"name": "Application.Intl.locale", "value": "cs"}, {"name": "Password.prefill", "value": "{\"username\":\"vladimir.buzalka@buzalka.cz\",\"type\":\"email\"}"}]}]}
|
|
||||||
Reference in New Issue
Block a user