Files
ordinaceprojekt/Insurance/StahováníZpráv/205 ČPZP/POSTUP.md
T
2026-04-20 15:41:13 +02:00

5.7 KiB
Raw Blame History

ČPZP — Automatické stahování zpráv

Co to dělá

Dva skripty které se přihlásí na portál ČPZP a stáhnou všechny zprávy ze schránek:

  1. 01_prihlaseni.py — přihlásí se certifikátem, uloží cookies do cpzp_cookies.json
  2. 02_stahuj_vse.py — použije cookies, projde schránky, stáhne soubory do Staženo/

Jak funguje přihlášení

Portál nepoužívá heslo — autentizuje certifikátem přes 3 kroky:

Krok 1 — Získej session a challenge

GET https://portal.cpzp.cz/app/login/
→ server nastaví cookie: PHPSESSID=...
→ v HTML stránce je vložen JS objekt s challengem a CSRF tokenem

Challenge je v HTML jako JS výraz (ne JSON):

CPZP = {
    settings : {
        certificateLoginKey : 'Prohlášení:'+ String.fromCharCode(13, 10) +
            'Tímto se přihlašuji k Portálu ČPZP'+ String.fromCharCode(13, 10) +
            ''+ String.fromCharCode(13, 10) +
            'Okamžik vygenerování tohoto prohlášení: 20.04.2026 14:52:47',
        ...
    }
}

CSRF token je v HTML formuláři:

<form name="frmPrihlasCert" method="post" action="/app/">
  <input name="csrfCert" type="hidden" value="42ead46f7d374805c5d9...">
  <input id="sign" name="sign" type="hidden" value="">
</form>

Krok 2 — Podpis certifikátem

Challenge (sestavená z JS výrazu) se podepíše jako PKCS7 / CMS SignedData:

  • Algoritmus: RSA + SHA-256
  • Typ: DetachedSignature (obsah není vložen do podpisu)
  • BEZ CA řetězu — pouze end-entity certifikát
  • Výsledný formát: PEM s hlavičkami (-----BEGIN PKCS7-----)
pem_podpis = (
    pkcs7.PKCS7SignatureBuilder()
    .set_data(challenge.encode("utf-8"))
    .add_signer(cert, private_key, hashes.SHA256())
    .sign(Encoding.PEM, [PKCS7Options.DetachedSignature])
)

⚠️ Na rozdíl od VoZP portál ČPZP očekává celý PEM string včetně hlaviček, ne jen base64 DER (přestože oboje přes NMSigner). Bez hlaviček vrátí 500.

Krok 3 — Přihlášení

POST https://portal.cpzp.cz/app/
Content-Type: application/x-www-form-urlencoded

csrfCert=<token_z_formulare>&sign=<pem_podpis>

Úspěch: odpověď neobsahuje "frmPrihlasCert" (login stránka)

Certifikát

Položka Hodnota
Soubor U:\ordinaceprojekt\Insurance\Certificates\MBQualifiedCert.pfx
Vlastník MUDr. Michaela Buzalková
Vydavatel I.CA EU Qualified CA2/RSA 06/2022
Platnost do 2027-01-16
Thumbprint 056ED80A3CDDE31DD36EECE0181B4E78D61122A7

Stahování souborů

02_stahuj_vse.py používá requests (bez Playwright) — portál nevyžaduje JS pro navigaci.

Schránky které se prochází

URL Název
/app/schranka/ Schránka klienta
/app/schranka-pzs/ Schránka PZS

Obě schránky obsahují stejné zprávy — skript deduplicuje podle ID zprávy.

Paginace

Portál zobrazuje 20 zpráv na stránku, stránkování přes ?offset=N:

GET /app/schranka/?offset=0    → zprávy 120
GET /app/schranka/?offset=20   → zprávy 2140
...

Detekce konce: pokud stránka neobsahuje žádné nové ID, zastav.

Struktura zprávy v seznamu

<tr id="message-69cd7aa38ec68a837b5d8cbc" class="mail-read status-done">
  <td>...</td>
  <td>zpracováno</td>
  <td>09305000 - MUDr. Michaela Buzalková</td>
  <td>VYÚČTOVÁNÍ ZDRAVOTNÍ PÉČE Ref. č. 26274350</td>
  <td>01.04.2026 22:05:42</td>
  <td><a href="/app/schranka/detail/69cd7aa38ec68a837b5d8cbc/">zobrazit detail</a></td>
</tr>

ID zprávy je hex string (24 znaků), ne číslo jako u VoZP.

Detail zprávy a stažení

GET /app/schranka/detail/{hex_id}/
→ stránka obsahuje odkaz na soubor

<a href="/app/schranka/protokol/?path=c387260ba8f041609a663038be79281c">
  ZU250168094V1.pdf          ← název souboru (nebo "26274350 (stáhnout protokol)")
</a>
GET /app/schranka/protokol/?path={hash}
→ vrátí soubor (PDF nebo HTML podle druhu zprávy)

Typy souborů

Druh zprávy Typ souboru Obsah
IČZ: ... Č.faktury: ... PDF Zúčtovací zpráva
VYÚČTOVÁNÍ ZDRAVOTNÍ PÉČE HTML Protokol přijetí vyúčtování
KLIENTELA HTML Protokol přijetí
Konečné vyúčtování PDF Závěrečné vyúčtování

Přípona se určuje podle textu linku (.pdf) nebo Content-Type odpovědi.

Pojmenování stažených souborů

YYYY-MM-DD Druh zprávy (Ref. XXXXXXXXX).přípona

Příklady:

2026-03-26 IČZ_ 09305000 Č.faktury_ 260027 (Ref. 26220064).pdf
2026-04-01 VYÚČTOVÁNÍ ZDRAVOTNÍ PÉČE (Ref. 26274350).html
2025-05-29 Konečné vyúčtování (Ref. 24774290).pdf

Znaky nepovolené ve Windows názvech (/ : * ? " < > |) se nahrazují podtržítkem.


Rozdíly oproti VoZP

VoZP ČPZP
Challenge zdroj JSON API (/json-api/prihlaseni/prihlasovaci-zprava) HTML stránka (JS výraz)
Challenge formát JSON string s \r\n JS string concatenation + String.fromCharCode
Podpis formát PEM s hlavičkami PEM s hlavičkami
Odeslání POST JSON na API endpoint POST form-data na /app/
CSRF ne ano (csrfCert)
ID zprávy číselné hex string (24 znaků)
Stahování Playwright + context.request.get() čisté requests
Typy souborů vždy HTML HTML i PDF

Závislosti

pip install requests cryptography beautifulsoup4

Spuštění

python 01_prihlaseni.py   # přihlásí, uloží cookies (nutné při expiraci session)
python 02_stahuj_vse.py   # stáhne vše, přeskočí již existující soubory

Session cookie (PHPSESSID) expiruje — pokud 02_stahuj_vse.py zahlásí "Cookies expirovala", spusť nejdřív 01_prihlaseni.py.