1# Projekt: Apify Actor — Telegram Channel Scraper (verified)
2
3**Vlastník:** Marek Hartmann
4**Založené:** 19. 8. 2026
5**Stav:** v0.6 — repo na GitHube, CI zelené, 46 testov, 8/8 živých stavov, Actor overený end-to-end pod Apify SDK; zostáva build a publikovanie na Apify
6**Repo:** https://github.com/marekhartmann-creator/telegram-verified-scraper (publikované 19. 8. 2026)
7**Časový rozpočet:** 2–4 dni
8**Peňažný rozpočet:** 0 € (podmienka: žiadna investícia pred prvým príjmom)
9
10---
11
12## 1. Cieľ
13
14Publikovať na Apify Store platený Actor, ktorý sťahuje príspevky z verejných
15Telegram kanálov, a zarobiť na ňom cez revenue share 80/20. Nie cvičenie —
16príjmový kanál a zároveň verejný dôkaz kvality do portfólia.
17
18## 2. Prečo práve Telegram (trhové dáta, overené 19. 8. 2026 cez api.apify.com/v2)
19
20Segment má preukázateľný obrat a jedného veľkého nespokojného hráča:
21
22
23|---|---|---|---|---|
24| tri_angle/telegram-scraper | 4 254 | 164 | 47 391 | **2,21** (16) |
25| lofomachines/telegram-keyword-search-scraper | 840 | **245** | 8 070 | 5,0 (1) |
26| webfinity/telegram-channel-content-media-v2 | 942 | 58 | 1 772 | 5,0 (7) |
27| truefetch/telegram-channel-message | 754 | 92 | 5 195 | 4,47 (3) |
28| automation-lab/telegram-scraper | 604 | 91 | 2 779 | 5,0 (2) |
29
30**Korekcia pôvodného predpokladu.** Vstupný prieskum hovoril o „diere bez
31dominantného konkurenta" a o hodnotení incumbenta 1,42. Overenie ukázalo:
32
33* hodnotenie incumbenta **stúplo na 2,21** a 30. 7. 2026 nasadili novú verziu —
34 Actor sa opravuje, nie je opustený;
35* **lofomachines získava viac nových používateľov mesačne než incumbent**
36 (245 vs 164) a existuje od februára 2026. Dopyt, ktorý incumbentovi uteká,
37 už má kam ísť.
38
39Diera teda nie je prázdna. Vstupujeme ako ~6. hráč do segmentu, kde traja majú
40hodnotenie 5,0. To je vedomé rozhodnutie, nie prehliadnutie.
41
42## 3. Reprodukované zlyhanie (to, na čom staviame)
43
44Overené 19. 8. 2026:
45
461. **Neexistujúci kanál nevracia chybu.** `t.me/s/<preklep>` vráti HTTP 200 a
47 normálnu stránku bez akéhokoľvek kanálového markupu. Naivný scraper napočíta
48 0 príspevkov, ohlási úspech a vyfakturuje. → Toto je hlavný vektor tichého
49 zlyhania a je reprodukovateľný na počkanie.
502. **ID príspevkov nie sú súvislé.** `?before=100` na georgenews vrátilo ID
51 80, 85, 95–97, 99 — diery po zmazaných a servisných správach. Stránkovanie
52 počítané aritmeticky (`min_id − veľkosť_stránky`) preskočí reálne príspevky.
533. Pôvodná sťažnosť („georgenews nevracia výsledky") **nie je dnes
54 reprodukovateľná** — kanál sa načíta normálne. Buď to opravili, alebo
55 používateľ zadal zlý vstup (čo je presne prípad č. 1).
56
57## 4. Rozsah
58
59**IN:** verejné kanály — príspevky, views, reakcie, media URL, forwardy,
60odpovede, edity, hashtagy, mentions, link preview; filter podľa dátumu a
61kľúčových slov.
62
63**OUT (natrvalo, nie „zatiaľ"):** členovia kanálov, používateľské profily,
64telefónne čísla, akékoľvek osobné údaje. Dôvod: GDPR + Telegram ToS + Marek je
65v EU. Napísané aj do listingu ako predajný argument pre EU firmy.
66
67**OUT (v1, kandidát na v2):** globálne vyhľadávanie naprieč Telegramom podľa
68kľúčového slova — ťažšia úloha a už ju drží lofomachines.
69
70## 5. Architektúra
71
72Štyri vrstvy, pričom hodnotu nesie 1. a 4., nie 2.:
73
741. **Preflight (`tg/preflight.py`)** — klasifikuje handle do 7 stavov ešte
75 predtým, než sa uverí akémukoľvek počtu príspevkov. Primárny signál: či `/s/`
76 stránka vôbec vyrenderovala `.tgme_channel_info` + `.tgme_channel_history`.
77 Ak nie, rozhoduje sa z obyčajnej `t.me/<handle>` stránky.
782. **Zber (`tg/fetch.py`, `tg/parse.py`)** — httpx + selectolax proti
79 server-renderovanému preview. **Zámerne bez prehliadača:** headless Chrome by
80 znásobil pamäť, a teda účet zákazníka, na stránkach, ktoré sú statické HTML.
81 Stránkovanie výhradne cez Telegramov vlastný `data-before` odkaz, nikdy
82 aritmetikou nad ID.
833. **Orchestrácia (`tg/scraper.py`)** — normalizácia handle, stránkovanie,
84 filtre, streamovanie dávok do datasetu počas behu.
854. **Verifikácia (`tg/verify.py`)** — rozhoduje verdikt `OK` /
86 `EMPTY_VERIFIED` / `PARTIAL` / `FAILED`. Kľúčové pravidlo: nula príspevkov je
87 platný výsledok **iba** ak stav je `PUBLIC_PREVIEWABLE`, aspoň jedna stránka
88 sa načítala a metadáta kanála neprotirečia (kanál hlásiaci 1 204 fotiek s
89 nulou príspevkov = zlyhanie načítania, nie prázdny kanál).
90
91`failOnUnreadableChannel=true` (default) → beh skončí ako FAILED s dôvodom.
92
93Toto je priamy prenos Marekovho read-back/verify vzoru z browser automation do
94scrapingu — rovnaká myšlienka, iný cieľ.
95
96## 6. Cenotvorba
97
98* Actor start: **$0** — konkurencia si účtuje $0,005–0,01 za štart, takže
99 neúspešný beh ich stojí peniaze. Nulový štart je marketingový argument aj
100 technický záväzok.
101* Za overený príspevok: **$0,002** ($2 / 1 000 výsledkov — presne stred pásma,
102 ktoré Apify uvádza ako bežné, $1–10 / 1 000).
103* Neúčtuje sa nič, čo neprešlo verifikáciou → sľub „prázdny beh je zadarmo"
104 vychádza z architektúry, nie z dobrej vôle.
105
106Konkurencia za výsledok: webfinity $0,01 · tri_angle $0,005 · lofomachines
107$0,0025 · automation-lab $0,001 · truefetch $0,00035.
108
109## 7. Očakávaný výnos (triezvo)
110
111Jeden používateľ s denným behom nad ~200 príspevkami ≈ **$12/mes hrubého**,
112z toho ~$9,60 Marekovi. Zisk teda závisí od počtu **opakujúcich sa** používateľov.
113
114* 1. mesiac: $5–25
115* 3. mesiac (pri 3–4 dobrých recenziách): $60–200
116* 6. mesiac pri dobrom ranku: $200–600
117* Najčastejší scenár na Apify: $0–15 mesačne donekonečna
118
119Benchmark: lofomachines má 8 070 behov/30 dní pri $0,0025 za výsledok — pri
120odhade 50–200 výsledkov na beh je to rádovo $1 000–4 000 hrubého mesačne, za pol
121roka od nuly. (Počet výsledkov na beh Apify verejne neukazuje — rád veličiny je
122podložený, presné číslo nie.)
123
124**Skutočná bariéra nie je technika, ale prvé tri recenzie a nájditeľnosť.**
125
126## 8. Stav a build log
127
128**19. 8. 2026**
129
130* Overené trhové dáta cez per-actor endpointy (nie store-search súhrny).
131* Reprodukované tiché zlyhanie na neexistujúcom handle + nesúvislé ID.
132* Postavené: `errors.py`, `preflight.py`, `parse.py`, `fetch.py`, `verify.py`,
133 `scraper.py`, `main.py`, Apify obal (actor.json, input_schema, dataset_schema,
134 pay_per_event, Dockerfile), README ako listing.
135* **36 pytest testov, zelené.** Vrátane priamej reprodukcie incumbentovho bugu:
136 `test_unknown_handle_fails_loudly_instead_of_returning_empty`.
137* Limit prostredia: cloudový kontajner nemá sieťový prístup na `t.me`. v0.1 bola
138 preto postavená proti ručne napísaným fixtures.
139
140**19. 8. 2026 — v0.2, živá verifikácia (Windows, Python 3.14, cez Bridge Runtime)**
141
142* 38 testov zelených aj na Windowse.
143* Živý beh proti reálnemu Telegramu: `durov` 25 príspevkov (ID 503–543, 2 diery),
144 `telegram` 25 (1 diera), `georgenews` 25 (2 diery, 3 media), `durov_russia`
145 25 (6 dier). Views, dátumy, ID a stránkovanie sedia.
146* **Dve chyby, ktoré by fixtures nikdy neodhalili:**
147 1. Reakcie sa parsovali na `.tgme_reactions_reaction`; Telegram v skutočnosti
148 renderuje `span.tgme_reaction` v troch tvaroch — `<i class="emoji"><b>😁</b></i>171`,
149 custom `<tg-emoji emoji-id="…">55.2K`, a platený `tgme_reaction_paid`
150 s ikonou hviezdy. Prepísané, počet sa berie ako textový uzol za emoji.
151 Predtým: `reakcie=0` na príspevku so 79 500 reakciami.
152 2. Klasifikátor označil neexistujúci handle ako `NOT_A_CHANNEL` namiesto
153 `NOT_FOUND`. Verdikt bol správne FAILED, ale správa bola zavádzajúca.
154 Skutočný podpis neexistujúceho handle (overený naživo): žiadny
155 `.tgme_page_title`, žiadny `.tgme_page_extra`, `og:image` =
156 `telegram.org/img/t_logo*.png` a veta "If you have Telegram, you can
157 contact @X right away." Fixtures prepísané na reálny markup.
158* Doplnené: `sys.stdout.reconfigure` v smoke teste (Windows konzola je cp1250 a
159 padala na emoji).
160* **Poučenie do listingu:** práve tieto dve chyby sú presne trieda chýb, ktorú
161 incumbent nezachytí — parser tichého vráti 0 reakcií a zle pomenovaný stav.
162 Verifikačná vrstva ich odhalila okamžite, lebo verdikt nesedel s obsahom.
163
164**19. 8. 2026 — v0.4, druhé kolo živej verifikácie**
165
166* Preverených 19 reálnych handle-ov, aby som našiel vzorky stavov, ktoré som
167 dovtedy len odhadoval. Výsledok: **klasifikátor mal vážnu chybu.**
168 * `rt_russian` (386 tisíc odberateľov) dostal verdikt **NOT_FOUND** — teda
169 "skontroluj si preklep" na kanáli, ktorý existuje. Príčina: Telegram tam
170 posiela rovnakú kostru stránky ako pri neexistujúcom handle, líši sa jedna
171 veta: *"you can **view posts by** @X"* (kanál existuje, preview nedáme)
172 oproti *"you can **contact** @X"* (nič tu nie je).
173 * `mdk` vracia rovno marketingovú stránku Telegramu bez `.tgme_page` —
174 handle je zablokovaný, nie neexistujúci. Nový podpis → `RESTRICTED`.
175 * `zerohedge` hovorí "view and join", ale má počet odberateľov → počítadlá
176 teraz prebíjajú boilerplate.
177 * Ironicky: bola to presne tá chyba, proti ktorej je celý produkt postavený,
178 len o krok vedľa — namiesto tichého prázdna nahlas nesprávny dôvod.
179* `scripts/smoke.py` je odteraz **živá regresná sada**: 8 handle-ov s očakávaným
180 stavom, pri nezhode končí exit kódom 1. Aktuálne **8/8**.
181* Overené naživo: PUBLIC_PREVIEWABLE, NOT_FOUND, EXISTS_NO_PREVIEW (dva rôzne
182 tvary), NOT_A_CHANNEL (skupina), RESTRICTED. Neoverené: PRIVATE, UNREACHABLE.
183* Pridaná **paralelizácia kanálov** (`maxConcurrency`, default 5). Telegram
184 round-tripy trvajú ~4-10 s na kanál; sériovo by zákazník platil compute za
185 čakanie.
186* **Dve chyby nájdené až prvým skutočným spustením Actora:**
187 1. `Dockerfile` mal `CMD python3 -m src.main` — to modul len naimportuje a
188 skončí. Actor by na Apify naštartoval a hneď dobehol bez práce. Správne
189 je `-m src`.
190 2. `create_proxy_configuration` vyhodí výnimku, keď nie je heslo k Apify
191 Proxy (lokálny beh, plán bez proxy) a zabije celý beh. Teraz je proxy
192 voliteľná — pri chybe sa loguje varovanie a ide sa priamo.
193* Pridané: GitHub Actions CI (pytest na 3.11-3.13), `.gitattributes` (LF),
194 ukážkový `storage/.../INPUT.json`, prvý git commit (40 súborov).
195
196**19. 8. 2026 — v0.6, prvý skutočný beh Actora**
197
198Spustené pod reálnym Apify SDK (4.0.1) v lokálnom režime. Toto odhalilo veci,
199ktoré ani testy, ani živý scraping nemohli:
200
201* `Dockerfile` mal `CMD python3 -m src.main` → modul sa naimportuje a proces
202 skončí. Na Apify by Actor „úspešne" dobehol za sekundu a neurobil nič.
203 Opravené na `-m src`.
204* `create_proxy_configuration` padne, keď nie je heslo k Apify Proxy. Zabíjalo
205 to celý beh. Proxy je teraz voliteľná.
206* `RUN_SUMMARY` sa ukladal bez `content_type`, čiže bez prípony `.json` a
207 neotvoriteľný v Console. Opravené.
208* `textHtml` zdvojnásobuje veľkosť každej položky → nový prepínač `includeHtml`,
209 default vypnutý.
210
211**Overenie sľubu produktu end-to-end:**
212
213
214|---|---|---|
215| 1 | `durov`, `telegram` | exit **0**, 50 overených príspevkov, 2/2 kanály |
216| 2 | `durov`, `georgnews_typo_xx` | exit **1**, beh FAILED s dôvodom |
217
218Druhý riadok je celý produkt: incumbent by na tom istom vstupe ohlásil úspech,
219vrátil neúplný dataset a vyfakturoval.
220
221**19. 8. 2026 — v0.7, nasadené na Apify**
222
223* Actor vytvorený z verejného GitHub repa (bez OAuth, cez „Another Git provider"
224 — verejné repo nepotrebuje deployment key).
225* **Build 0.0.1: Succeeded** za 15 s, $0,003.
226* **Prvý ostrý beh na Apify: Succeeded, 101 výsledkov, 18 s, $0,002.** Dataset
227 view „Posts" sedí, reakcie sa parsujú (80 200 / 227 700), views aj ID sedia.
228* Vyplnené Display information: názov `Telegram Channel Scraper - Verified Posts`
229 (kľúčové slová dopredu kvôli vyhľadávaniu v Store), popis do 300 znakov,
230 kategórie Social media / Automation / Developer tools.
231* Apify si vyžiadal **output schema** pred publikovaním. Doplnené:
232 `.actor/dataset_schema.json` s plnou definíciou polí (predtým prázdne `fields`)
233 a `.actor/key_value_store_schema.json` pre `RUN_SUMMARY`.
234* Pri tom padlo rozhodnutie: **verifikačné reporty už nejdú do datasetu.**
235 Dataset je odteraz čisto jeden riadok = jeden príspevok (a jediné, za čo sa
236 platí); reporty žijú v key-value store. Export je tým pádom čistý.
237
238## 9. Čo ďalej (poradie)
239
2401. ~~Živý smoke test~~ — hotové 19. 8. 2026, dve chyby nájdené a opravené.
2412. ~~Doplniť živé prípady~~ — hotové, chýba už len vzorka súkromného kanála
242 (`PRIVATE`); jeho fixture je stále odhad, nie zachytený markup.
2433. **Blokované na Marekovi:** `gh auth login` (GitHub CLI je nainštalovaný, ale
244 neprihlásený) → vytvoriť repo a pushnúť. Commit je pripravený.
2454. Prepojiť repo s Apify, build.
2465. Nastaviť pay-per-event v Apify Console podľa `.actor/pay_per_event.json`.
2476. Publikovať, doplniť listing (README) a screenshot výstupu.
2487. Prvé recenzie: požiadať o feedback v Apify Discorde a v jednom OSINT/Telegram
249 komunitnom vlákne — bez toho Actor nikto nenájde.
250
251## 10. Riziká
252
253* **Telegram zmení markup** → parser prestane fungovať. Zmiernenie: každé pole
254 je voliteľné, žiadny crash; ale tiché prázdno by bolo fatálne pre celý sľub
255 produktu — preto verifikačná vrstva kontroluje aj to, či hlavička vôbec
256 vyrenderovala.
257* **Rate limiting / blokovanie IP** pri veľkých behoch → Apify proxy je v inpute,
258 ale netestované pod záťažou.
259* **Segment sa zaplní skôr, než získa recenzie.** Toto je hlavné biznis riziko,
260 nie technické.
261
262## 11. Obmedzenia prostredia
263
264* **Bridge Runtime beží pod účtom `SYSTEM`** (`C:\WINDOWS\system32\config\systemprofile`),
265 nie pod Marekovým používateľom. Nevidí teda jeho `gh auth login` ani Git
266 Credential Manager — testy, scraping a lokálne behy cez Bridge fungujú, ale
267 `git push`, `gh` a čokoľvek autentifikované musí spustiť Marek sám.
268 Riešiteľné prehodením služby na jeho účet alebo vlastným `GH_TOKEN` pre Bridge.
269* Cloudový kontajner Cowork session nemá sieťový prístup na `t.me`, preto všetka
270 živá verifikácia prebieha cez Bridge na Marekovom PC.
271
272## 12. Publikovanie
273
274* Repo: pushnuté 19. 8. 2026, 39 súborov, 2 commity, `main`.
275* GitHub Actions `tests`: **success** (pytest na Python 3.11/3.12/3.13, Linux) —
276 prvé potvrdenie, že kód beží aj mimo Windows/3.14, kde bol vyvíjaný.
277
278
279## 13. Publikovane (19. 8. 2026)
280
281**https://apify.com/marekhartmann/telegram-channel-scraper** - verejne na Apify Store,
282zadarmo pocas early access (pay per usage), bez monetizacie.
283
284Cesta od "checklist je zeleny" k publikovanemu Actorovi odhalila styri veci:
285
2861. **Output schema** - Apify vyzaduje pole `output` v `.actor/actor.json`; dataset view
287 schema mu nestaci. Ich validator navyse vyzaduje `type` v kazdej polozke, hoci
288 minimalny priklad v ich dokumentacii ho neuvadza.
2892. **Key-value store schema** musi mat `actorKeyValueStoreSchemaVersion`.
2903. **`?clean=true` v output sablone** rozbilo kartu Output - Apify si parametre v URL
291 typuje a `true` precitala ako text. Beh pritom presiel; dataset bol v poriadku, len
292 sa zakaznikovi nezobrazil. Tichá chyba v konfiguracii produktu, ktory je proti tichym
293 chybam postaveny.
2944. **Deployment key dialog** blokoval buildy - Apify pyta SSH kluc do GitHub repa. Repo
295 je verejne a HTTPS klonovanie funguje, takze "Don't add".
296
297Stav po dokonceni: build **0.0.7** (`latest`), posledny beh Succeeded, 100 vysledkov,
29811 s, $0.001. Karta Output sa vykresluje spravne pod pohladom "Verified posts".
299
300**Ochrana proti driftu Telegramu:** tyzdenny GitHub Actions workflow `live-smoke`
301(pondelok 6:17 UTC) prebehne `scripts/smoke.py` proti zivemu t.me a spadne, ked sa
302ktorykolvek z osmich handle-ov zacne klasifikovat inak. Unit testy dokazuju, ze parser
303sedi na markup zachyteny 19. 8. 2026; toto dokazuje, ze Telegram ten markup este ma.
304
305**Predvoleny vstup** je zamerne dvojkanalovy (`durov`, `telegram`): Apify denne
306autotestuje publikovany Actor a po troch behoch bez neprazdneho datasetu ho oznaci
307"under maintenance". Actor je pritom navrhnuty tak, aby pri necitatelnom kanale zlyhal -
308jeden kanal by tu kontrolu zhodil prave vtedy, keby sa Actor zachoval spravne.