Files
ordinaceprojekt/Euni/NOTES.md
T
2026-06-17 11:53:54 +02:00

5.2 KiB

Euni — stahování a tracking kurzů z euni.cz

Přihlásí se na euni.cz, projde kurzy, vytěží odkazy + metadata a stahuje obsah (PDF/prezentace a videa Vimeo/YouTube). Vše se trackuje v MongoDB EUNI, takže stahování je idempotentní — skript ví, co už má, a netahá dvakrát.

Soubory

Soubor Popis
euni_stahni.py hlavní pipeline: login → scrape → ingest do Mongo → stahování → záloha do SeaweedFS
euni_db.py připojení a operace nad MongoDB EUNI (kolekce, indexy, upserty)
euni_seaweed.py nahrávání/stahování souborů do SeaweedFS (filer HTTP API)
euni_restore.py obnova všech souborů ze SeaweedFS na disk (na jakémkoli PC)
euni_report.py dashboard: přehled stavu (kolik staženo/čeká/přeskočeno)
.env EUNI_USERNAME, EUNI_PASSWORD (v .gitignore)
euni_kurzy.json poslední inventura (záloha; primární zdroj je Mongo)
stazeno/ stažený obsah, stazeno/<id>-<slug>/{dokumenty,videa}/

Závislosti

python -m pip install -U requests beautifulsoup4 python-dotenv yt-dlp static-ffmpeg pymongo

Video stahuje sdílený modul ../Video/stahni_video.py (yt-dlp + static-ffmpeg, soukromá videa sám přeskočí).

MongoDB EUNI

Server mongodb://192.168.1.76:27017 (bez hesla), DB EUNI. Lze přepsat env proměnnou EUNI_MONGO_URI.

Kolekce kurzy (1 dokument na kurz)

_id = euni ID kurzu. Pole: slug, nazev, url, profese[], autor, autor_medailonek_url, datum_publikace, revidovano, akreditace, kredity, pocet_videi, pocet_dokumentu, first_seen, updated_at.

Kolekce materialy (1 dokument na soubor)

Unikátní index {kurz_id, klic}. Pole: kurz_id, kurz_nazev, druh (video|dokument), platforma (vimeo|youtube), klic (vimeo:ID / youtube:ID / doc:hash), zdroj_url, watch_url, popis, pripona, stav, duvod, soubor, velikost_b, pokusy, posledni_chyba, first_seen, updated_at, stazeno_at.

Stavy: cekastazeno / preskoceno (soukromé video) / chyba.

SeaweedFS reference (po nahrání kopie): seaweed_path (cesta ve filer = identifikátor pro vyžádání, např. euni/5618-.../dokumenty/x.pdf), seaweed_fids (fid chunků = čísla souborů v SeaweedFS), seaweed_md5, seaweed_size, seaweed_at.

SeaweedFS záloha + obnova

Každý stažený soubor se nahraje do SeaweedFS (filer na Unraidu, default http://192.168.1.50:8888, přepíše env EUNI_FILER). Do Mongo se k materiálu uloží seaweed_path + seaweed_fids, takže soubor lze kdykoli vyžádat.

  • Strukturu na disku zrcadlí cesta: euni/<id>-<slug>/<typ>/<soubor>.
  • Filer metadata (mapa cesta→chunky) jsou v Mongo DB seaweedfs na 192.168.1.76; bloby na poli Unraidu. (Setup: U:\\PythonProject\\Janssen\\SeaweedFS\\.)
  • Pozn.: přímý přístup přes raw fid/volume zvenčí nefunguje (volume se uvnitř Dockeru jmenuje seaweed-volume); proto se čte/zapisuje přes filer.

Obnova kdekoliv (stačí síť na Mongo + filer):

python euni_restore.py                 # vše → ./obnoveno
python euni_restore.py --out D:\Euni   # jiný cíl
python euni_restore.py --kurz 5618     # jen jeden kurz
python euni_restore.py --dry-run       # jen výpis

Backfill (dohrát do SeaweedFS soubory stažené dřív):

python euni_stahni.py --seaweed-backfill --from-json

Idempotence

  • Scrape dělá upsert: nový materiál → ceka; existující si drží stav (nepřepíše stažené). Lze tedy bez obav scrapovat opakovaně.
  • Stahování bere jen stav: ceka (a volitelně chyba pro retry).

Použití

python euni_stahni.py --scrape-only            # jen inventura → Mongo + JSON
python euni_stahni.py --no-videos              # scrape + stáhne jen dokumenty
python euni_stahni.py                          # scrape + dokumenty + videa
python euni_stahni.py --from-json --no-videos  # přeskočí scrape, stáhne z Mongo/JSON
python euni_stahni.py --professions all        # všechny profese (2,4,5,6,7)
python euni_stahni.py --limit 3                # jen prvních 3 kurzy (test)
python euni_stahni.py --no-mongo               # bez zápisu do Mongo
python euni_report.py                          # přehled stavu
python euni_report.py --soukroma               # seznam přeskočených videí

Jak to funguje (ověřeno)

  • Login /sign/ — formulář se parsuje (kopírují se skrytá Nette pole _do).
  • Seznam kurzů — signál studyAreaList-nextPage vrací JSON snippet, stránkuje se dokud přibývají kurzy (profese: 2=Lékař, 4=Farmaceut, 5/6=studenti, 7=NLZP).
  • Detail kurzu — server-rendered HTML; videa z <iframe> (u Vimea se zachová ?h= hash), dokumenty z přímých odkazů i /redirect/<base64>.
  • Metadata z bloků lecture-info-labellecture-info-mark.

Úskalí

  • Vimeo dává oddělené video/audio HLS → nutný ffmpeg (řeší static-ffmpeg). Domain-restricted videa se stahují s referer https://www.euni.cz/.
  • Soukromá videa (autor je zamkl) nejdou stáhnout — skript je označí preskoceno s důvodem, nepadá.
  • Anotace kurzu na stránce není (jen obecný text webu) → neukládá se.
  • Diakritika v názvech: v konzoli cp1250 OK; výpis má pojistku proti pádu.