# ============================================================================= # Název: sipiq_download_v2.1.py # Verze: 2.1 # Datum: 2026-06-19 # Autor: Claude Code (pro MUDr. Vladimíra Buzalku) # Popis: Automatické stažení SIPIQ survey reportu (CSV) z Qualtrics přes # Playwright. Přihlásí se (username/password), otevře Data & Analysis # studie 77242113UCO3002 (SV_9AdeNaNyohp5fNQ), spustí Export & Import → # Export Data → CSV → Download a stažený soubor uloží s timestampem do # U:\Dropbox\!!!Days\Downloads Z230\. # # v2.1: přepínač --import → po úspěšném stažení rovnou spustí # sipiq_import_v1.3.py --csv "" (delta import do Mongo, # NEpřesouvá soubor). --scope se předá importu (default czsk). # # Proč Playwright a ne API: účet NEMÁ povolené API na úrovni účtu; # interní export běží jen na session cookies + interní fileUrl # (riptooth.service.consul) nedostupné zvenčí. Playwright se přihlásí # sám (řeší expiraci session) a stažení nechá na prohlížeči. # # Credentials: ROOT .env (QUALTRICS_USER / QUALTRICS_PASS), fallback # na zabudované hodnoty účtu sipiq. # Verze 1.0 (requests/API) a 2.0 (bez --import) přesunuty do TRASH. # ============================================================================= import argparse import os import subprocess import sys from datetime import datetime from playwright.sync_api import sync_playwright, TimeoutError as PWTimeout try: from dotenv import load_dotenv _ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) load_dotenv(os.path.join(_ROOT, ".env")) except Exception: pass DC = "janssenfeasibility.co1" SURVEY = "SV_9AdeNaNyohp5fNQ" USER = os.environ.get("QUALTRICS_USER", "77242113uco3002_sipiq") PWD = os.environ.get("QUALTRICS_PASS", "77242113uco3002_sipiq") LOGIN_URL = "https://login.qualtrics.com/login" RESP_URL = f"https://{DC}.qualtrics.com/responses/#/surveys/{SURVEY}" OUT_DIR = r"U:\Dropbox\!!!Days\Downloads Z230" HERE = os.path.dirname(os.path.abspath(__file__)) PROFILE = os.path.join(HERE, "qualtrics_profile") IMPORT_SCRIPT = os.path.join(HERE, "sipiq_import_v1.3.py") DEBUG_DIR = HERE def dbg(page, name): try: page.screenshot(path=os.path.join(DEBUG_DIR, f"_dl_{name}.png")) except Exception: pass def ensure_login(page): page.goto(LOGIN_URL, timeout=120000) page.wait_for_load_state("domcontentloaded") page.wait_for_timeout(3000) field = page.locator("#UserName, input[name='username'], #username").first if field.is_visible(timeout=5000): print("Přihlašuji se…") field.fill(USER) page.locator("#UserPassword, input[name='password'], #password").first.fill(PWD) page.locator("#loginButton, button[type='submit'], #login-button").first.click() page.wait_for_timeout(8000) page.wait_for_load_state("domcontentloaded") else: print("Session aktivní, přihlášení přeskočeno.") def open_data_table(page): page.goto(RESP_URL, timeout=120000) page.wait_for_load_state("domcontentloaded") page.get_by_role("button", name="Export & Import").wait_for(timeout=120000) page.wait_for_timeout(2000) print("Data & Analysis načteno.") def do_export(page): page.get_by_role("button", name="Export & Import").click() page.wait_for_timeout(1500) dbg(page, "01_menu") page.get_by_text("Export Data", exact=False).first.click() page.wait_for_timeout(3000) dbg(page, "02_modal") try: page.get_by_role("tab", name="CSV").click(timeout=5000) except PWTimeout: try: page.get_by_text("CSV", exact=True).first.click(timeout=5000) except Exception: print("CSV tab nenalezen, spoléhám na default.") page.wait_for_timeout(1500) dbg(page, "03_csv") print("Spouštím Download…") with page.expect_download(timeout=180000) as dl_info: page.get_by_role("button", name="Download").last.click() return dl_info.value def download(headless): os.makedirs(OUT_DIR, exist_ok=True) with sync_playwright() as pw: ctx = pw.chromium.launch_persistent_context( PROFILE, headless=headless, accept_downloads=True, args=["--start-maximized"], no_viewport=not headless) page = ctx.pages[0] if ctx.pages else ctx.new_page() try: ensure_login(page) open_data_table(page) dl = do_export(page) stamp = datetime.now().strftime("%Y-%m-%d_%H%M%S") suggested = dl.suggested_filename or "sipiq_export.csv" target = os.path.join(OUT_DIR, f"{stamp} {suggested}") dl.save_as(target) print("Staženo:", target) return target except Exception as e: dbg(page, "99_error") print("CHYBA při stahování:", repr(e), file=sys.stderr) raise finally: page.wait_for_timeout(1500) ctx.close() def run_import(csv_path, scope, dry_run): cmd = [sys.executable, IMPORT_SCRIPT, "--csv", csv_path, "--scope", scope] if dry_run: cmd.append("--dry-run") print("\n=== IMPORT do Mongo ===") print("Spouštím:", " ".join(f'"{c}"' if " " in c else c for c in cmd)) rc = subprocess.call(cmd) if rc != 0: print(f"CHYBA: import skončil s kódem {rc}.", file=sys.stderr) return rc def main(): ap = argparse.ArgumentParser(description="Stažení SIPIQ CSV z Qualtrics (+ volitelný import)") ap.add_argument("--headless", action="store_true", help="bez okna (pro scheduler)") ap.add_argument("--import", dest="do_import", action="store_true", help="po stažení rovnou naimportovat do Mongo (sipiq_import_v1.3 --csv)") ap.add_argument("--scope", choices=["czsk", "all"], default="czsk", help="scope pro import (default czsk)") ap.add_argument("--dry-run", action="store_true", help="import jen jako náhled (předá se sipiq_import --dry-run)") args = ap.parse_args() csv_path = download(args.headless) if args.do_import: rc = run_import(csv_path, args.scope, args.dry_run) sys.exit(rc) else: print("\nHOTOVO. (Import nespuštěn — přidej --import pro napojení na Mongo.)") if __name__ == "__main__": main()