domain priorisierung
Vollständige Domain-Extraktion: Implementiert über die neue Methode _get_full_domain, die nun den kompletten Domainnamen (inklusive TLD) liefert (z. B. "heimbach.com"). Normalisierung der Firmennamen: Einführung der Funktion normalize_company_name, welche gängige Firmierungsformen (z. B. GmbH, AG, Aktiengesellschaft, Co. KG, mbH, & Co. KG, e.V., Limited, Ltd, Inc, Corp, Corporation, Gruppe) entfernt. Dies führt zu einem konsistenten Vergleich zwischen den Unternehmensdaten und Wikipedia-Titeln. Verbesserte Artikelvalidierung: In _validate_article werden nun: Infobox-Links sowie externe Links geprüft, ob sie den vollständigen Domainnamen enthalten (ohne Dateilinks). Der Vergleich der Wikipedia-Titel und des Firmennamens erfolgt auf Basis der normalisierten Namen. Ein dynamischer Schwellenwert wird verwendet (0.60 statt 0.65), wenn ein definitiver Link-Match gefunden wurde.
This commit is contained in:
@@ -12,7 +12,7 @@ import csv
|
||||
|
||||
# ==================== KONFIGURATION ====================
|
||||
class Config:
|
||||
VERSION = "1.0.14"
|
||||
VERSION = "1.1.3"
|
||||
LANG = "de"
|
||||
CREDENTIALS_FILE = "service_account.json"
|
||||
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
|
||||
@@ -51,6 +51,17 @@ def clean_text(text):
|
||||
text = re.sub(r'\s+', ' ', text).strip()
|
||||
return text if text else "k.A."
|
||||
|
||||
def normalize_company_name(name):
|
||||
"""Entfernt gängige Firmierungsformen und normalisiert den Namen."""
|
||||
if not name:
|
||||
return ""
|
||||
# Liste gängiger Firmierungsformen, inklusive "Gruppe"
|
||||
pattern = r'\b(gmbh|ag|aktiengesellschaft|co\.?\s*kg|mbh|&\s*co\.?\s*kg|e\.v\.|limited|ltd|inc|corp|corporation|gruppe)\b'
|
||||
normalized = re.sub(pattern, '', name, flags=re.IGNORECASE)
|
||||
normalized = re.sub(r'[\-–]', ' ', normalized) # Ersetze Bindestriche durch Leerzeichen
|
||||
normalized = re.sub(r'\s+', ' ', normalized).strip()
|
||||
return normalized.lower()
|
||||
|
||||
# ==================== GOOGLE SHEET HANDLER ====================
|
||||
class GoogleSheetHandler:
|
||||
"""Handhabung der Google Sheets Interaktion"""
|
||||
@@ -83,72 +94,86 @@ class WikipediaScraper:
|
||||
def __init__(self):
|
||||
wikipedia.set_lang(Config.LANG)
|
||||
|
||||
def _get_domain_key(self, website):
|
||||
"""Extrahiert den Domain-Key aus der URL (ohne Protokoll und www)"""
|
||||
def _get_full_domain(self, website):
|
||||
"""Extrahiert den vollständigen Domainnamen (inklusive Topleveldomain) aus der URL."""
|
||||
if not website:
|
||||
return ""
|
||||
website = website.lower().strip()
|
||||
website = re.sub(r'^https?:\/\/', '', website)
|
||||
website = re.sub(r'^www\.', '', website)
|
||||
parts = website.split(".")
|
||||
if len(parts) > 1:
|
||||
return parts[0]
|
||||
website = website.split('/')[0]
|
||||
return website
|
||||
|
||||
def _generate_search_terms(self, company_name, website):
|
||||
"""
|
||||
Generiert Suchbegriffe in folgender Reihenfolge:
|
||||
1. Domain-Key (falls vorhanden)
|
||||
2. Die ersten zwei Wörter des Firmennamens
|
||||
3. Der vollständige Firmenname
|
||||
1. Vollständiger Domainname (z. B. "heimbach.com")
|
||||
2. Die ersten zwei Wörter des normalisierten Firmennamens
|
||||
3. Der vollständige, normalisierte Firmenname
|
||||
"""
|
||||
terms = []
|
||||
domain_key = self._get_domain_key(website)
|
||||
if domain_key:
|
||||
terms.append(domain_key)
|
||||
candidate = " ".join(company_name.split()[:2]).strip()
|
||||
full_domain = self._get_full_domain(website)
|
||||
if full_domain:
|
||||
terms.append(full_domain)
|
||||
normalized_name = normalize_company_name(company_name)
|
||||
candidate = " ".join(normalized_name.split()[:2]).strip()
|
||||
if candidate and candidate not in terms:
|
||||
terms.append(candidate)
|
||||
original = company_name.strip()
|
||||
if original and original not in terms:
|
||||
terms.append(original)
|
||||
if normalized_name and normalized_name not in terms:
|
||||
terms.append(normalized_name)
|
||||
debug_print(f"Generierte Suchbegriffe: {terms}")
|
||||
return terms
|
||||
|
||||
def _validate_article(self, page, company_name, domain_key):
|
||||
def _validate_article(self, page, company_name, website):
|
||||
"""
|
||||
Validiert den Artikel:
|
||||
- Sucht in der Infobox nach externen Links, die den Domain-Key enthalten.
|
||||
Wird der Domain-Key gefunden, wird der Artikel als definitiv korrekt akzeptiert.
|
||||
- Andernfalls wird der Wikipedia-Titel mit dem Firmennamen mittels Ähnlichkeitsvergleich geprüft.
|
||||
- Sucht in der Infobox und in den externen Links nach Links, die den vollständigen Domainnamen enthalten.
|
||||
Wird ein solcher Link gefunden, wird ein niedrigerer Schwellenwert (0.60) angewendet.
|
||||
- Andernfalls werden der normalisierte Wikipedia-Titel und der normalisierte Firmenname verglichen.
|
||||
"""
|
||||
# Zuerst: Prüfe, ob der Domain-Key in den Links der Infobox vorkommt.
|
||||
if domain_key:
|
||||
full_domain = self._get_full_domain(website)
|
||||
domain_found = False
|
||||
if full_domain:
|
||||
try:
|
||||
html_raw = requests.get(page.url).text
|
||||
soup = BeautifulSoup(html_raw, Config.HTML_PARSER)
|
||||
# Suche in der Infobox
|
||||
infobox = soup.find('table', class_=lambda c: c and 'infobox' in c.lower())
|
||||
if infobox:
|
||||
links = infobox.find_all('a', href=True)
|
||||
for link in links:
|
||||
href = link['href'].lower()
|
||||
if domain_key in href:
|
||||
href = link.get('href').lower()
|
||||
# Überspringe Dateilinks
|
||||
if href.startswith('/wiki/datei:'):
|
||||
continue
|
||||
if full_domain in href:
|
||||
debug_print(f"Definitiver Link-Match in Infobox gefunden: {href}")
|
||||
return True
|
||||
domain_found = True
|
||||
break
|
||||
# Suche in den externen Links, falls vorhanden
|
||||
if not domain_found and hasattr(page, 'externallinks'):
|
||||
for ext_link in page.externallinks:
|
||||
ext_link = ext_link.lower()
|
||||
if full_domain in ext_link:
|
||||
debug_print(f"Definitiver Link-Match in externen Links gefunden: {ext_link}")
|
||||
domain_found = True
|
||||
break
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler beim Extrahieren des Infobox-Links: {str(e)}")
|
||||
# Falls kein definitiver Link-Match, mache den Ähnlichkeitsvergleich:
|
||||
clean_title = re.sub(r'\(.*?\)', '', page.title).lower()
|
||||
clean_company = company_name.lower().strip()
|
||||
similarity = SequenceMatcher(None, clean_title, clean_company).ratio()
|
||||
debug_print(f"Ähnlichkeit: {similarity:.2f} ({clean_title} vs {clean_company})")
|
||||
return similarity >= Config.SIMILARITY_THRESHOLD
|
||||
debug_print(f"Fehler beim Extrahieren von Links: {str(e)}")
|
||||
|
||||
# Normalisierte Namen für Vergleich
|
||||
normalized_title = normalize_company_name(page.title)
|
||||
normalized_company = normalize_company_name(company_name)
|
||||
similarity = SequenceMatcher(None, normalized_title, normalized_company).ratio()
|
||||
debug_print(f"Ähnlichkeit (normalisiert): {similarity:.2f} ({normalized_title} vs {normalized_company})")
|
||||
|
||||
threshold = 0.60 if domain_found else Config.SIMILARITY_THRESHOLD
|
||||
return similarity >= threshold
|
||||
|
||||
@retry_on_failure
|
||||
def search_company_article(self, company_name, website):
|
||||
"""Sucht mit optimierten Suchbegriffen (Domain-Key, Candidate, Name) nach dem Wikipedia-Artikel."""
|
||||
"""Sucht mit optimierten Suchbegriffen (vollständiger Domainname, Candidate, normalisierter Name) nach dem Wikipedia-Artikel."""
|
||||
search_terms = self._generate_search_terms(company_name, website)
|
||||
domain_key = self._get_domain_key(website)
|
||||
for term in search_terms:
|
||||
try:
|
||||
results = wikipedia.search(term, results=Config.WIKIPEDIA_SEARCH_RESULTS)
|
||||
@@ -156,7 +181,7 @@ class WikipediaScraper:
|
||||
for title in results:
|
||||
try:
|
||||
page = wikipedia.page(title, auto_suggest=False)
|
||||
if self._validate_article(page, company_name, domain_key):
|
||||
if self._validate_article(page, company_name, website):
|
||||
return page
|
||||
except (wikipedia.exceptions.DisambiguationError, wikipedia.exceptions.PageError) as e:
|
||||
debug_print(f"Seitenfehler: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user