Umsatz- und Mitarbeiterextraktion optimiert – Umsatz in Mio € und Mitarbeiterzahl als ganze Zahl (v1
Umsatz-Extraktion: Der numerische Teil wird mittels einer neuen Helper-Funktion extract_numeric_value extrahiert. Wenn im Text "mrd" (Milliarden) vorkommt, wird der extrahierte Wert mit 1000 multipliziert; wenn "mio" vorkommt, bleibt der Wert unverändert. Wenn keine Einheit angegeben ist, wird angenommen, dass der Wert in Euro ist, und er wird durch 1.000.000 geteilt. Beispiel: Aus "10,0 Mrd. Euro (2021/22)" wird der Wert 10,0 → 10 * 1000 = 10000 Mio. Mitarbeiter-Extraktion: Der numerische Teil wird ebenfalls mit extract_numeric_value extrahiert, ohne Skalierung. Beispiel: Aus "4.175 (2021/22)" wird "4.175" erkannt und die Punkte als Tausendertrennzeichen entfernt, sodass "4175" resultiert. Re-Evaluierungsmodus: Alle Zeilen mit "x" in Spalte A werden verarbeitet (ohne Abfrage der Zeilenzahl). Zusätzlich wird im Re-Evaluierungsmodus der komplette Infobox-Inhalt in der Konsole ausgegeben. Spaltenanpassungen: Im normalen Modus: Firmenname in Spalte A, Website in Spalte B; Ausgabe in G:K, Datum in N, Version in Q. Im Re‑Evaluierungsmodus: Firmenname in Spalte B, Website in Spalte C; Ausgabe in H:L, Datum in O, Version in R.
This commit is contained in:
@@ -12,7 +12,7 @@ import csv
|
||||
|
||||
# ==================== KONFIGURATION ====================
|
||||
class Config:
|
||||
VERSION = "1.1.11" # Neue Version mit verbesserter Umsatz- und Mitarbeiterextraktion
|
||||
VERSION = "1.1.12" # Neue Version: Optimierte Umsatz- und Mitarbeiterextraktion
|
||||
LANG = "de"
|
||||
CREDENTIALS_FILE = "service_account.json"
|
||||
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
|
||||
@@ -69,6 +69,45 @@ def normalize_company_name(name):
|
||||
normalized = re.sub(r'\s+', ' ', normalized).strip()
|
||||
return normalized.lower()
|
||||
|
||||
def extract_numeric_value(raw_value, is_umsatz=False):
|
||||
"""
|
||||
Extrahiert den numerischen Wert aus raw_value.
|
||||
- Bei Umsatz: Wenn "mrd" im Text vorkommt, multipliziere mit 1000;
|
||||
wenn weder "mio" noch "mrd" gefunden werden, wird angenommen, dass der Wert in Euro ist, und durch 1e6 geteilt.
|
||||
- Bei Mitarbeiterzahl: Entferne Tausendertrennzeichen und gib den ganzzahligen Wert zurück.
|
||||
"""
|
||||
raw = raw_value.lower()
|
||||
match = re.search(r'([\d.,]+)', raw)
|
||||
if not match:
|
||||
return raw_value.strip()
|
||||
num_str = match.group(1)
|
||||
# Wenn Komma vorhanden, nehmen wir an, es handelt sich um einen Dezimaltrenner (mit eventuell Punkten als Tausendertrennzeichen)
|
||||
if ',' in num_str:
|
||||
num_str = num_str.replace('.', '').replace(',', '.')
|
||||
try:
|
||||
num = float(num_str)
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler bei der Umwandlung von {num_str}: {e}")
|
||||
return raw_value.strip()
|
||||
else:
|
||||
# Keine Kommas: Entferne alle Punkte (als Tausendertrennzeichen)
|
||||
num_str = num_str.replace('.', '')
|
||||
try:
|
||||
num = float(num_str)
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler bei der Umwandlung von {num_str}: {e}")
|
||||
return raw_value.strip()
|
||||
if is_umsatz:
|
||||
if "mrd" in raw or "milliarden" in raw:
|
||||
num *= 1000
|
||||
elif "mio" in raw or "millionen" in raw:
|
||||
pass
|
||||
else:
|
||||
num /= 1e6
|
||||
return str(int(round(num)))
|
||||
else:
|
||||
return str(int(round(num)))
|
||||
|
||||
# ==================== GOOGLE SHEET HANDLER ====================
|
||||
class GoogleSheetHandler:
|
||||
def __init__(self):
|
||||
@@ -176,58 +215,19 @@ class WikipediaScraper:
|
||||
clean_val = re.sub(r'\[.*?\]|\(.*?\)', '', raw_value)
|
||||
return ' '.join(clean_val.split()).strip()
|
||||
if target == 'umsatz':
|
||||
raw = raw_value.lower()
|
||||
match = re.search(r'([\d.,]+)', raw)
|
||||
if match:
|
||||
num_str = match.group(1)
|
||||
# Falls Komma vorhanden: Punkte als Tausendertrennzeichen entfernen, Komma als Dezimaltrenner ersetzen
|
||||
if ',' in num_str:
|
||||
num_str = num_str.replace('.', '').replace(',', '.')
|
||||
else:
|
||||
num_str = num_str.replace(' ', '').replace('.', '')
|
||||
try:
|
||||
num = float(num_str)
|
||||
except Exception as e:
|
||||
debug_print(f"Umsatz-Umwandlungsfehler: {e} für {num_str}")
|
||||
return raw_value.strip()
|
||||
if 'mrd' in raw or 'milliarden' in raw:
|
||||
num *= 1000
|
||||
elif 'mio' in raw or 'millionen' in raw:
|
||||
pass
|
||||
else:
|
||||
num /= 1e6
|
||||
return str(int(round(num)))
|
||||
return raw_value.strip()
|
||||
# Extrahiere den numerischen Teil und berechne den Wert in Mio €
|
||||
return extract_numeric_value(raw_value, is_umsatz=True)
|
||||
if target == 'mitarbeiter':
|
||||
raw = raw_value.lower()
|
||||
# Spezifisch nach "mitarbeiterzahl" suchen, um den direkt folgenden Zahlenwert zu extrahieren.
|
||||
match = re.search(r'(?:mitarbeiterzahl|mitarbeiter)[^\d]*([\d.,\s]+)', raw)
|
||||
if match:
|
||||
num_str = match.group(1)
|
||||
# Entferne Tausendertrennzeichen (Punkte oder Leerzeichen)
|
||||
num_str = num_str.replace(" ", "")
|
||||
# Falls es nur Punkte und keine Kommas gibt, behandeln wir diese als Tausendertrennzeichen.
|
||||
if '.' in num_str and ',' not in num_str:
|
||||
num_str = num_str.replace('.', '')
|
||||
# Entferne eventuell verbleibende nicht-numerische Zeichen.
|
||||
num_str = re.sub(r'[^\d]', '', num_str)
|
||||
if num_str:
|
||||
debug_print(f"Mitarbeiterzahl gefunden: {num_str} in Text: {raw_value}")
|
||||
return num_str
|
||||
# Fallback: Falls keine spezifische Suche funktioniert, versuche die erste Zahl zu extrahieren.
|
||||
match = re.search(r'(\d{1,3}(?:\.\d{3})+|\d+)', raw)
|
||||
if match:
|
||||
num_str = match.group(1)
|
||||
if '.' in num_str and ',' not in num_str:
|
||||
num_str = num_str.replace('.', '')
|
||||
return num_str
|
||||
return raw_value.strip()
|
||||
# Extrahiere den numerischen Teil; erwarte Format wie "4.175 (2021/22)"
|
||||
return extract_numeric_value(raw_value, is_umsatz=False)
|
||||
return "k.A."
|
||||
|
||||
def extract_full_infobox(self, soup):
|
||||
infobox = soup.find('table', class_=lambda c: c and any(kw in c.lower() for kw in ['infobox', 'vcard', 'unternehmen']))
|
||||
if not infobox:
|
||||
return "k.A."
|
||||
return clean_text(infobox.get_text(separator=' | '))
|
||||
|
||||
def extract_fields_from_infobox_text(self, infobox_text, field_names):
|
||||
result = {}
|
||||
tokens = [token.strip() for token in infobox_text.split("|") if token.strip()]
|
||||
@@ -239,6 +239,7 @@ class WikipediaScraper:
|
||||
j += 1
|
||||
result[field] = tokens[j] if j < len(tokens) else "k.A."
|
||||
return result
|
||||
|
||||
def extract_company_data(self, page_url):
|
||||
if not page_url:
|
||||
return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'full_infobox': 'k.A.'}
|
||||
@@ -262,6 +263,7 @@ class WikipediaScraper:
|
||||
except Exception as e:
|
||||
debug_print(f"Extraktionsfehler: {str(e)}")
|
||||
return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.', 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'full_infobox': 'k.A.'}
|
||||
|
||||
@retry_on_failure
|
||||
def search_company_article(self, company_name, website):
|
||||
search_terms = self._generate_search_terms(company_name, website)
|
||||
@@ -282,6 +284,63 @@ class WikipediaScraper:
|
||||
continue
|
||||
return None
|
||||
|
||||
# ==================== Neue Helper-Funktion für numerische Werte ====================
|
||||
def extract_numeric_value(raw_value, is_umsatz=False):
|
||||
"""
|
||||
Extrahiert den numerischen Wert aus raw_value.
|
||||
- Falls ein Komma vorhanden ist, werden Punkte als Tausendertrennzeichen entfernt und das Komma als Dezimaltrenner genutzt.
|
||||
- Falls kein Komma vorhanden ist, werden alle Punkte entfernt (als Tausendertrennzeichen).
|
||||
- Für Umsatz: Wenn "mrd" im Text vorkommt, wird der Wert mit 1000 multipliziert; falls keine Einheit angegeben ist, wird angenommen, dass der Wert in Euro ist und durch 1e6 geteilt.
|
||||
- Für Mitarbeiter: Der extrahierte numerische Wert wird als ganze Zahl zurückgegeben.
|
||||
"""
|
||||
raw = raw_value.lower()
|
||||
match = re.search(r'([\d.,]+)', raw)
|
||||
if not match:
|
||||
return raw_value.strip()
|
||||
num_str = match.group(1)
|
||||
# Wenn Komma vorhanden, behandeln wir es als Dezimaltrenner
|
||||
if ',' in num_str:
|
||||
num_str = num_str.replace('.', '').replace(',', '.')
|
||||
try:
|
||||
num = float(num_str)
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler bei der Umwandlung von {num_str}: {e}")
|
||||
return raw_value.strip()
|
||||
else:
|
||||
# Entferne alle Punkte (als Tausendertrennzeichen)
|
||||
num_str = num_str.replace('.', '')
|
||||
try:
|
||||
num = float(num_str)
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler bei der Umwandlung von {num_str}: {e}")
|
||||
return raw_value.strip()
|
||||
if is_umsatz:
|
||||
if "mrd" in raw or "milliarden" in raw:
|
||||
num *= 1000
|
||||
elif "mio" in raw or "millionen" in raw:
|
||||
pass
|
||||
else:
|
||||
num /= 1e6
|
||||
return str(int(round(num)))
|
||||
else:
|
||||
return str(int(round(num)))
|
||||
|
||||
# ==================== GOOGLE SHEET HANDLER ====================
|
||||
class GoogleSheetHandler:
|
||||
def __init__(self):
|
||||
self.sheet = None
|
||||
self.sheet_values = []
|
||||
self._connect()
|
||||
def _connect(self):
|
||||
scope = ["https://www.googleapis.com/auth/spreadsheets"]
|
||||
creds = ServiceAccountCredentials.from_json_keyfile_name(Config.CREDENTIALS_FILE, scope)
|
||||
self.sheet = gspread.authorize(creds).open_by_url(Config.SHEET_URL).sheet1
|
||||
self.sheet_values = self.sheet.get_all_values()
|
||||
def get_start_index(self):
|
||||
filled_n = [row[13] if len(row) > 13 else '' for row in self.sheet_values[1:]]
|
||||
return next((i + 1 for i, v in enumerate(filled_n, start=1) if not str(v).strip()), len(filled_n) + 1)
|
||||
# Update-Aufrufe erfolgen separat.
|
||||
|
||||
# ==================== DATA PROCESSOR ====================
|
||||
class DataProcessor:
|
||||
def __init__(self):
|
||||
@@ -347,7 +406,7 @@ if __name__ == "__main__":
|
||||
print("Ungültige Eingabe. Bitte eine Zahl eingeben.")
|
||||
exit(1)
|
||||
else:
|
||||
num_rows = None # Im Re-Evaluierungsmodus werden alle markierten Zeilen verarbeitet.
|
||||
num_rows = None
|
||||
processor = DataProcessor()
|
||||
processor.process_rows(num_rows)
|
||||
print("\n✅ Wikipedia-Auswertung abgeschlossen")
|
||||
|
||||
Reference in New Issue
Block a user