Analýza článků z dezinformačních webů před/ve volebním období

Cíle

  • Zaměření: Volby do poslanecké sněmovny ČR 2025
  • Období od začátku června do konce září (volby 3. a 4. října)
  • Analýza obsahu článků na dezinformačních webech
  • Zkoumání, zda weby mají tendenci podporovat/diskreditovat určitou stranu / určitého kandidáta
  • Zjistit, zda se témata ve vybraném období liší od témat po/před vybraném období
  • Průzkum, zda a mezi jakými weby se objevují stejné příspěvky
  • Vytvořit znovupoužitelný framework *

Idea provedení

  1. Identifikovat zajímavé/relevantní weby
  2. Stáhnout články z vybraných webů
  3. Použít LLM/AI pro extrahování narativů z článků
    (rozdělení na "pozitivní" a "negativní")
  4. Manuální analýza/statistika
  5. Profit!

Volba programovacího jazyka: Python

1. Zajímavé weby

Nadační fond nezávislé žurnalistiky (NFNZ) má seznam "konspiračních a dezinformačních serverů". Celkem 22 webů:

  • AC 24
  • Aeronet *
  • Arfa
  • Časopis Šifra
  • Czech Free Press
  • CZ 24 News
  • Infokurýr
  • Nová republika
  • Outsider Media
  • Otevři svou mysl
  • Pravdivě
  • Protiproud *
  • Pravý prostor
  • První zprávy
  • Skrytá pravda
  • Slovanské nebe
  • Sputnik News
  • Svobodný vysílač
  • Tadesco
  • TOP News
  • Věk světla
  • Zvědavec

2. Scraping

Jako zajímavé časové období jsem vybral 1. 6. až 5. 9. 2025.

Z každého článku extrahován titulek, datum, text a tagy.

Nekompletní seznam problémů:
  • Cloudflare proxy (=> knihovna/balíček cloudscraper)
  • "Vlastní" proxy (=> deobfuskace JS a počítání challenge)
  • Rate limiting (vyústil v blokace na nějaký čas)

Celkově staženo 16046 článků (~125 MB).

Během průzkumů jsem narazil na několik perliček:

  • Dostupné "smazané stránky" (http://.../__trashedXYZ)
  • "Bezpečné šifrování pomocí MD5"
  • SQL injection

3. Analýza článků

Moje poprvé s LLM/AI. Navíc chudý student využívající free tiery.

Modely gemini-2.5-flash a gemini-3-flash-preview.

  • Google API dovoluje 20 API requestů na den per model per "projekt"
  • Vytvořeny 3 projekty (víc mi Google nepovolil)
  • => 20*2*3 = 120 requestů na den
  • ... ale to na 16000 článků nestačí.
  • => více článků v jednom requestu

Modelu předán titulek, text a tagy článku.


                        Vstupem je několik extrahovaných článků z webu. Úkol je určit vůči kterým tématů jsou jednotlivé články pozitivní (např. vyzdvihování úspěchů, propagace/podpora dané osoby/věci, ...) a vůči kterým negativní (např. diskreditování, ponižování, označování dané osoby jako lháře / dané věci jako leži, ...). Články budou často emociálně zabarvené, což indikuje prezenci pozitivní/negativní postoje vůči nějakému tématu. U každého článku omez výstup na maximálně 5 nejvýraznějších pozitivních a 5 nejvýraznějších negativních témat. **Je velmi důležité všechny články analyzovat postupně a odděleně - obsah jednoho článku nesmí ovlivnit analýzu jiného!**

                        Články jsou z doby, kdy v ČR probíhaly kampaně pro volby poslanecké sněmovny, mezi hlavní témata (mimo jiné) patří:
                        - Politické ČR osoby, např. prezident Petr Pavel, premiér Petr Fiala, Vít Rakušan, Jiří Raichl, Tomio Okamura, Kateřina Konečná, ...
                        - Politické ČR strany, např. ODS, SPOLU, SPD, STAN, STAČILO!, ...
                        - Pohledy na geopolitiku, primárně názory např. na Rusko, Čínu, Ameriku, Evropskou Unii, ...

                        Je nutné dbát na separaci jednotlivých článků. **Každý článek musí být analyzovaný zvlášť!**
                        

Přes Google SDK API předáno modelu i JSON schéma:


                        class SingleArticleAnalysisOutput(BaseModel):
                            id: int = Field(description="ID článku; Musí být stejné jako ID článku ve vstupu")
                            positive: list[str] = Field(description="Seznam témat vyobrazených pozitivně")
                            negative: list[str] = Field(description="Seznam témat vyobrazených negativně")
                            relevant: bool = Field(
                                description="`true` pokud článek míří na volby v ČR, jinak `false`"
                            )


                        class AnalysisOutput(BaseModel):
                            outputs: list[SingleArticleAnalysisOutput] = Field(
                                description="Výsledek pro každý článek ze vstupu"
                            )
                        

Problémy:

  • Občas se nějaký článek ztratil (=> dočasné ID pro články)
  • Model občas "escapnul" JSON (uvozovky ve výstupu)
  • 503 UNAVAILABLE - The model is overloaded
  • Někdy se vrátila prázdná odpověď bez chyby

Problémy kvůli špatnému promptu:

  • Model se někdy rozhodl odpovídat anglicky
  • Model někdy přidal i "vysvětlení"
  • Výstup je značně nenormalizovaný

Další zajímavosti:

  • Zkoušen i model "Gemma 3 27B", ovšem velmi předzaujat (články o válce na Ukrajině => vždy negativní pohled na Rusko i když ho článek oslavoval)
  • Z počátku jsem zkoušel 50 článků najednou, ovšem to skončilo katastrofou (primárně halucinace)
  • Nakonec 20 článků per request (ale i tak se články "ztrácejí")
  • Analýza celkově trvala něco přes týden

4. Statistika

"Nekvalitní" (resp. nečistá) data z předchozí fáze. Problémů špatného promptu jsem si všiml až příliš pozdě.

Filtrace jen podle "relevant" flagu.

Provedl jsem normalizace a základní seskupení pomocí kódu, pak následovaly pokusy o seskupení pomocí LLM, které ale nedopadly tak dobře, jak bych chtěl... Nakonec zdlouhavá manuální práce.

5. Profit!

Většina webů se nezaměřovala výhradně na otázky voleb/politiky. Výjimku tvoří weby Pravý prostor,
Protiproud a Skrytá pravda.

V počtu relevantních/zajímavých článků jsem nepozoroval žádný výrazný trend, krom počátku léta, kdy byl počet článků větší.

Podobně tak weby nebyly v počtu článků v průběhu času intenzivnější. Výjimku tvoří TOPNews, který s blížícími se volbami kvantitu článků zvyšoval.

Nejčastější témata

Pozitivní

  • Rusko (738)
  • Donald Trump (510)
  • SPD (412)
  • STAČILO! (412)
  • Vladimir Putin (323)
  • Andrej Babiš (210)
  • ANO (200)
  • Tomio Okamura (167)

Negativní

  • Petr Fiala (1851)
  • Evropská unie (1354)
  • Vláda (1219)
  • Ukrajina (739)
  • ODS (696)
  • NATO (534)
  • Vít Rakušan (507)
  • Petr Pavel (485)

Celkově

  • Petr Fiala (1890)
  • Evropská unie (1416)
  • Vláda (1230)
  • Rusko (826)
  • Ukrajina (799)
  • ODS (726)
  • Donald Trump (691)
  • NATO (566)

Skóre jednotlivých vybraných stran/politků

(pozitivní pohled = +1; negativní pohled = -1)
  • STAČILO! (379)
  • SPD (366)
  • ANO (122)
  • Motoristé (64)
  • Piráti (-169)
  • STAN (-362)
  • ODS (-666)
  • Tomio Okamura (150)
  • Kateřina Konečná (145)
  • Andrej Babiš (83)
  • Petr Pavel (-457)
  • Vít Rakušan (-499)
  • Petr Fiala (-1812)

Nejčastější témata spolu:

  • Evropská unie + Petr Fiala (577)
  • Petr Fiala + Vláda (574)
  • ODS + Petr Fiala (472)
  • Petr Fiala + Vít Rakušan (390)
  • Rusko + Ukrajina (383)
  • Evropská unie + Rusko (353)
  • Evropská unie + Vláda (323)
  • Donald Trump + Evropská unie (323)
  • Evropská unie + Green Deal (299)
  • Donald Trump + Rusko (299)

Shrnutí

Ověřil se "přepoklad", že weby budou značně pro-Ruské - jak v obecných tématech, tak i politických tématech ČR.

Z mé analýzy se nejeví, že by weby "silně reagovali na volby" (ovšem analyzoval jsem jen relativně krátké období).

Obecně tak na těchto webech byl silně kritizován Petr Fiala, Evropská unie a (předvolební) vláda obecně. Naopak velice pozitivně bylo vyobrazováno Rusko, Donald Trump a (předvolební) nevládní strany.

Z technického hlediska jsem vytvořil kód pro provedení této analýzy - troufám si tvrdit, že kód lze relativně jednoduše aplikovat na podobné analýzy, ovšem rozhodně se nejedná o "framework", kde by existovala jedna funkce do_analysis().

Za výstup zkoumání také považuji zjištění, že volba LLM modelu může mít drastický efekt na výsledek (viz silná zaujatost Gemma modelu proti Rusku).

Konec

Děkuji za pozornost