A témamodellezés segítségével megtalálhatjuk a rejtett mintákat és témákat a dokumentumokban. Ebben a blogbejegyzésben bemutatok egy egyszerű Python programot, amely lehetővé teszi a témamodellezést HTML forrásokon, feltérképezhetjük a kulcsszavakat és a témákat a weboldalakon, ezáltal könnyebben értelmezhetjük az online tartalmakat.

A felhasználó megadhat egy listát az URL-ekről és az azokhoz kapcsolódó címkékről. A programban a BeautifulSoupot használjuk a weboldalak letöltésére, majd preprocesszáljuk a szöveget a stop szavak eltávolításával és tokenizálással. A témák azonosítására a Gensim modult választottam. Az LDA (Latent Dirichlet Allocation) algoritmust alkalmazzuk a témamodellezésre.

Hozzunk létre egy projektkönyvtárat:

mkdir topic
cd topic

Majd a szükséges virtuális környezetet:

python3 -m venv .venv
source .venv/bin/activate

A következő könyvtárakat kell telepíteni a program használatához:

pip install beautifulsoup4
pip install gensim
pip install nltk
pip install requests

Hozzunk létre egy topic.py fájlt a projekt mappájában. A teljes példakód:

#!/usr/bin/env python3

import string
import argparse
import requests
from bs4 import BeautifulSoup
import gensim
from gensim import corpora
from gensim.models import LdaModel
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import nltk
nltk.download("stopwords")
nltk.download('punkt')

# Magyar stopwords lista beolvasása
with open('magyar_stopwords.txt', 'r', encoding='utf-8') as stopwords_file:
    magyar_stopwords = stopwords_file.read().splitlines()

def download_and_preprocess(url):
    # HTML tartalom letöltése
    response = requests.get(url)
    html_content = response.text

    # HTML tartalom feldolgozása a BeautifulSoup segítségével
    soup = BeautifulSoup(html_content, "html.parser")

    # Hasznos szövegrész kinyerése (pl. címek és paragrafusok)
    useful_text = ""
    for element in soup.find_all(["h1", "h2", "h3", "p"]):
        useful_text += element.get_text() + " "

    return useful_text

def preprocess_text(text):
    # Tokenizálás
    tokens = word_tokenize(text.lower())
    # Stop szavak és szóközök eltávolítása
    tokens = [word for word in tokens if word not in magyar_stopwords and word not in string.punctuation]
    return tokens

def perform_topic_modeling(text_tokens, num_topics=5):
    dictionary = corpora.Dictionary([text_tokens])
    corpus = [dictionary.doc2bow(text_tokens)]
    lda_model = LdaModel(corpus, num_topics=num_topics, id2word=dictionary)
    return lda_model

def main():
    parser = argparse.ArgumentParser(description='Témamodellezés HTML tartalmak alapján')
    parser.add_argument('file', type=argparse.FileType('r'), help='A txt fájl elérési útja')
    parser.add_argument('--topics', type=int, default=5, help='Témák száma')
    
    args = parser.parse_args()
    
    url_topics = {}  # URL és hozzájuk rendelt témák tárolása
    
    for line in args.file:
        parts = line.strip().split()  # URL és címke elválasztása
        url = parts[0]
        label = parts[1] if len(parts) > 1 else url  # Címke, vagy az URL, ha nincs megadva
        
        useful_text = download_and_preprocess(url)
        text_tokens = preprocess_text(useful_text)
        lda_model = perform_topic_modeling(text_tokens, args.topics)

        topics = lda_model.show_topics()
        
        # Témák az URL alapján
        url_topics[url] = []
        for i, topic in enumerate(topics):
            url_topics[url].append(f'Téma {i + 1}: {topic}')

    # Összefoglaló az összes témáról a teljes corpusban
    print('Témák a teljes corpusban:')
    for url, topics in url_topics.items():
        print(f'{url} témái:')
        for topic in topics:
            print(topic)
        print('\n')

if __name__ == '__main__':
    main()

Szükség lesz még két fájlra: a magyar_stopwords.txt és az url_labels.txt. A fájlok hozzáadása, melyeket szintén a projekt gyökérkönyvtárában kell létrehozni:

touch magyar_stopwords.txt
touch url_labels.txt

Példa az url_labels.txt tartalmára:

# url_labels.txt
http://www.magyarorszag.hu/
http://www.magyarorszag.hu/nyugat/

Példa a magyar_stopwords.txt tartalmára:

# magyar_stopwords.txt
is
és
...
új
újra
után
utána
utolsó

A program használata:

python3 topic.py <input_file> --topics <num_topics>

Ahol <input_file> az url_labels.txt fájl elérési útvonala, és a <num_topics> a kívánt témák száma.

A kód működési elve a következő:

  1. Beolvassa a megadott URL-eket és az azokhoz rendelt címkéket az url_labels.txt fájlból.
  2. Letölti az URL-ek tartalmát és előfeldolgozza a szöveget.
  3. Témamodellezi az egyes URL-ek tartalmát a gensim segítségével.
  4. Kiírja az összes URL-hez rendelt témát.

Segítség a stopwords fájl feltöltéséhez:

Link

Példa a program kimenetére:

python3 topic.py url_labels.txt --topics 3
[nltk_data] Downloading package stopwords to /home/zsolt/nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
[nltk_data] Downloading package punkt to /home/zsolt/nltk_data...
[nltk_data]   Package punkt is already up-to-date!
Témák a teljes corpusban:
https://telex.hu/komplex/2023/10/15/varroda-textilipar-divatipar-kornyezetszennyezes-globalizacio-ujrahasznositas témái:
Téma 1: (0, '0.003*"magyar" + 0.003*"divatipar" + 0.003*"készült" + 0.003*"része" + 0.002*"termékek" + 0.002*"ugyanakkor" + 0.002*"fashion" + 0.002*"gyártás" + 0.002*"káros" + 0.002*"ellátási"')
Téma 2: (1, '0.003*"divatipar" + 0.002*"cég" + 0.002*"ugyanakkor" + 0.002*"ruhák" + 0.002*"magyar" + 0.002*"része" + 0.002*"gyártás" + 0.002*"ellátási" + 0.002*"óceáni" + 0.002*"természetes"')
Téma 3: (2, '0.003*"magyar" + 0.003*"készült" + 0.003*"divatipar" + 0.003*"része" + 0.002*"termékek" + 0.002*"gyártás" + 0.002*"óceáni" + 0.002*"korábban" + 0.002*"ugyanakkor" + 0.002*"fenntartható"')


https://telex.hu/kulfold/2023/10/15/lengyelorszag-valasztas-elorejelzes-kaczynski-pis-tusk-ko témái:
Téma 1: (0, '0.006*"pis" + 0.006*"lengyel" + 0.005*"lengyelország" + 0.004*"állami" + 0.004*"harmadik" + 0.004*"ellenzék" + 0.003*"varsó" + 0.003*"tusk" + 0.003*"polgári" + 0.003*"európai"')
Téma 2: (1, '0.009*"pis" + 0.007*"lengyel" + 0.004*"lengyelország" + 0.004*"ellenzék" + 0.004*"ukrán" + 0.003*"harmadik" + 0.003*"polgári" + 0.003*"varsó" + 0.003*"állami" + 0.003*"tusk"')
Téma 3: (2, '0.009*"pis" + 0.007*"lengyel" + 0.005*"ellenzék" + 0.004*"lengyelország" + 0.004*"harmadik" + 0.004*"tusk" + 0.003*"kormány" + 0.003*"ukrán" + 0.003*"európai" + 0.003*"elmúlt"')


https://transtelex.ro/eletmod/2023/10/15/buszkeseg-es-beton-szociofoto-avasi-falvak témái:
Téma 1: (0, '0.005*"avasi" + 0.004*"călinescu" + 0.004*"generáció" + 0.004*"ioana" + 0.003*"petruț" + 0.003*"avasiak" + 0.003*"beton" + 0.003*"két" + 0.003*"hagyományos" + 0.003*"külföldön"')
Téma 2: (1, '0.006*"avasi" + 0.005*"călinescu" + 0.005*"generáció" + 0.004*"ioana" + 0.004*"petruț" + 0.003*"beton" + 0.003*"avasiak" + 0.002*"két" + 0.002*"házak" + 0.002*"év"')
Téma 3: (2, '0.005*"avasi" + 0.005*"călinescu" + 0.004*"generáció" + 0.004*"avasiak" + 0.004*"hagyományos" + 0.004*"petruț" + 0.003*"beton" + 0.003*"ők" + 0.003*"ioana" + 0.003*"külföldön"')


https://telex.hu/kulfold/2023/10/15/izraeli-palesztin-konfliktus-9-nap-percrol-percre-gazai-ovezet témái:
Téma 1: (0, '0.012*"izraeli" + 0.007*"hamász" + 0.006*"gázai" + 0.006*"izrael" + 0.004*"fruzsina" + 0.004*"hadsereg" + 0.003*"előd" + 0.003*"vasárnap" + 0.003*"idf" + 0.003*"északi"')
Téma 2: (1, '0.015*"izraeli" + 0.007*"gázai" + 0.007*"hamász" + 0.006*"hadsereg" + 0.005*"idf" + 0.004*"fruzsina" + 0.004*"előd" + 0.004*"izrael" + 0.004*"vasárnap" + 0.003*"bbc"')
Téma 3: (2, '0.020*"izraeli" + 0.009*"hamász" + 0.009*"gázai" + 0.007*"izrael" + 0.007*"előd" + 0.006*"fruzsina" + 0.005*"hadsereg" + 0.005*"idf" + 0.003*"vasárnap" + 0.003*"közölte"')