8.8 KiB
download_test_results_v1.2.py — dokumentace
Verze: 1.2 · Datum: 2026-05-29
Umístění: U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.2.py
Změny v1.2 oproti 1.1: přidán paralelní běh přes sharding (
--shard N --of M). Skript lze spustit ve více procesech současně, každý zpracuje svůj podíl reportů a používá vlastní profil. Spouští se přes launcherrun_test_results_parallel_v1.0.py. Změny v1.1 oproti 1.0: druhá studie 35472 (MDD) + report Microbiology.
1. Účel
Automatické stažení reportů Test Results z portálu Labcorp Sponsor Portal
(xsp.labcorp.com). Skript projde 2 studie × jejich centra × 2 typy reportu,
u každého vyexportuje grid do CSV a uloží ho timestampovaný do Source/.
| Studie | Interní ID | Význam | Počet center |
|---|---|---|---|
| UC | 36940 |
77242113UCO3001 | 12 |
| MDD | 35472 |
druhá studie | 5 |
Typy reportu: Standard (/standard-test-results) a Microbiology (/microbiology).
Celkem: (12 + 5) × 2 = 34 reportů (prázdná centra se přeskakují, viz 6.5).
2. Spuštění
2a) Paralelně (doporučeno — rychlejší)
Přes launcher, který rozjede 4 procesy (každý ve vlastním okně):
U:\PythonProject\Janssen\.venv\Scripts\python.exe ^
U:\PythonProject\Janssen\Covance_UCO3001\run_test_results_parallel_v1.0.py
2b) Serialně (jeden proces, jako dřív)
U:\PythonProject\Janssen\.venv\Scripts\python.exe ^
U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.2.py
2c) Jeden konkrétní shard ručně
…\python.exe download_test_results_v1.2.py --shard 2 --of 4
- Prohlížeč běží viditelně (
headless=False), maximalizovaný. - Persistent profile — session přežívá (viz sekce 4).
3. Paralelní běh (sharding) — jak funguje
3.1 Rozdělení práce
Argumenty --shard N --of M rozkrojí seznam všech 34 reportů:
REPORTS = ALL_REPORTS[SHARD - 1::OF]
Tj. shard 1 z 4 vezme reporty na indexech 0, 4, 8, … ; shard 2 indexy 1, 5, 9, …
Rovnoměrné rozdělení, žádný report neudělají dva shardy. Bez argumentů
(--of 1) běží serialně přes všech 34.
3.2 Proč nestačily 4 taby v jednom procesu
Playwright sync API je blokující — wait_for_* drží jediné vlákno celou
dobu čekání, takže 4 taby v jednom sync skriptu by se stejně střídaly sériově
(čekání by se sčítala, ne překrývala). Skutečná paralelnost vyžaduje buď async
API (přepis logiky), nebo — jak je zvoleno zde — 4 nezávislé procesy, kde
souběh zajišťuje OS.
3.3 Profil per shard (povinné)
Chrome zamyká adresář profilu → dvě běžící instance nemohou sdílet jeden profil. Proto:
| Běh | Profil |
|---|---|
serialní (--of 1) |
browser_profile/ (původní) |
shard N (--of M>1) |
browser_profile_{N}/ |
3.4 Login (varianta B)
Session se mezi profily nesdílí. Každý shard se proto při prvním spuštění
přihlásí sám (login je jen heslem, žádné MFA). Po prvním běhu už session
zůstane uložená v browser_profile_{N}/, takže další běhy login přeskočí
(is_visible() check). Launcher startuje procesy s rozestupem (STAGGER_S),
aby se OKTA login nezahltil 4 současnými požadavky.
3.5 Launcher run_test_results_parallel_v1.0.py
N_SHARDS = 4— počet souběžných procesů (oken).STAGGER_S = 4— rozestup mezi starty (s).- Každý proces se spustí v novém konzolovém okně (
CREATE_NEW_CONSOLE) → logy se neprolínají; navíc každý log má prefix[S{shard}/{of}]. - Launcher počká, až všechny dobíhnou, a vypíše souhrn (které shardy selhaly
dle
returncode).
3.6 Reálné zrychlení
Ne přesně 4× — export běží na serveru a velká centra generují hodně řádků, takže reálně spíš 2–3×. Server může souběžné exporty throttlovat.
4. Výstupní soubory
Formát názvu (timestamp + popisný název):
{YYYY-MM-DD_HHMMSS} sponsor-study-{STUDY}-test-results-{SITE_ID}-{TYP}.csv
{TYP} = standard nebo microbiology. Všechny shardy ukládají do stejného
adresáře Source/; timestamp + unikátní názvy (site/typ) zaručují, že nedojde ke
kolizi. Staré soubory se nikdy nemažou (verzování přes timestamp).
5. Průběh jednoho reportu (kroky + logging)
| Fáze | Co dělá |
|---|---|
| START | vypíše shard/of, profil, počet reportů; spustí prohlížeč |
| LOGIN | otevře login; pokud je session aktivní, přihlášení přeskočí |
| KROK 1/5 | navigace na report URL |
| KROK 2/5 | čeká na .ag-row nebo prázdný grid („No Data"); pak stabilizace počtu |
| KROK 3/5 | klik na viditelné tři tečky (more_horiz) → menu |
| KROK 4/5 | klik na viditelné „Export to CSV" → zachytí download |
| KROK 5/5 | uloží soubor do OUT_DIR |
| KONEC | souhrn hotovo X/Y (shard N/M) + seznam selhaných |
Log u každého reportu: === Centrum 930557 / microbiology (studie 36940) ===,
prefixovaný [S{shard}/{of}] při paralelním běhu.
6. Klíčové technické poznatky (PROČ to tak je) — ověřeno přes Chrome MCP
Stránka test-results je Angular SPA s MDL a tabulkou AG Grid. Microbiology záložka má stejnou strukturu jako Standard.
6.1 Čekání na data = řádky AG Gridu
- Data načtena, jakmile se objeví
div.ag-row(count 0 → N). - Řádky jsou
position-absolute→ Playwright je nepovažuje za „visible":- ❌
wait_for_selector("div.ag-row")(default visible) timeoutuje. - ✅
wait_for_function("() => document.querySelectorAll('div.ag-row').length > 0").
- ❌
- Stabilizace: počet se čte co 2 s, dokud se 2× neshodne.
- Počet
.ag-rowje zastropený (~153) virtuálním renderem — NENÍ to skutečný počet záznamů. Export do CSV ale vyexportuje VŠECHNY řádky (ověřeno: různé velikosti CSV).
6.2 „Fetching Data" / spinner — NEPLATÍ pro tuto stránku
Na test-results NENÍ text „Fetching Data" (je jen na samples reportu).
<loading-bar> jen problikne → nespoléhat. Signál = .ag-row.
6.3 Tři tečky (export) — DVA <ag-export>
2× <ag-export> (1 skrytý) → filtr na viditelnost:
✅ page.locator("ag-export button:visible", has_text="more_horiz").first.click()
6.4 „Export to CSV" — DVĚ položky v DOM
2× mdl-menu-item (1 skrytá) →
✅ page.locator("mdl-menu-item:visible", has_text="Export to CSV").first.click()
(❌ get_by_text → strict mode violation.)
6.5 Prázdné centrum (ověřeno přes Chrome MCP na centru 930551)
- No-rows overlay s textem „No Data" ve
.ag-overlay-no-rows-wrapper. - ⚠️ Třída NENÍ
.ag-overlay-no-rows-center. - ⚠️ Text NENÍ v
.ag-body-viewport(ten je prázdný,height: 1px). - ⚠️ Na stránce 2 overlaye (1 skrytý) → kontrola
offsetParent !== null. - Detekce (KROK 2):
() => { if (document.querySelectorAll('div.ag-row').length > 0) return false; return [...document.querySelectorAll('.ag-overlay-no-rows-wrapper')] .some(e => e.offsetParent !== null); } - KROK 2 čeká na
.ag-rowNEBO tuto detekci → prázdné centrum nečeká 120 s.
7. Login logika (sdílená napříč Covance skripty)
page.goto(LOGIN_URL); page.wait_for_load_state("networkidle")
if not page.get_by_label("Email").is_visible():
return # session aktivní → login přeskočit
# jinak: Email → Next → Password → Verify → wait redirect (code= zmizí z URL)
is_visible() (ne kontrola URL — po redirectu zůstává xsp.covance.com).
8. Chrome flagy proti „Restore pages" / broken session
--disable-restore-session-state
--disable-session-crashed-bubble
9. Robustnost
- Každý report v
try/except→ chyba u jednoho nezastaví zbytek shardu. - Souhrn na konci:
hotovo X/Y (shard N/M)+SELHALA centra: site/typ, …. - Launcher hlídá
returncodekaždého shardu.
10. Možná budoucí rozšíření
- Více/méně procesů: změnit
N_SHARDSv launcheru (profily_1.._N). - Další studie / centra / typ reportu: přidat do
STUDIES/REPORT_TYPES. - Vyčistit profily: smazat
browser_profile_*/(vynutí nový login).
11. Příbuzné skripty (stejná složka / portál)
| Skript | Co stahuje |
|---|---|
download_samples_report_v1.1.py |
All Samples (sampletracking) |
download_kit_inventory_v2.1.py |
Kit inventory |
download_equeries_report_v1.1.py |
eQuery reporty (zdroj SITE_IDS pro 36940) |
download_test_results_v1.2.py |
tento — Test Results (Standard + Microbiology, 2 studie, sharding) |
run_test_results_parallel_v1.0.py |
launcher 4 paralelních shardů test-results |