This commit is contained in:
2025-04-19 17:49:33 +00:00
parent fada980dc6
commit 5d0768aa7c

View File

@@ -1749,9 +1749,9 @@ class WikipediaScraper:
def _extract_infobox_value(self, soup, target):
"""
Extrahiert gezielt Branche, Umsatz oder Mitarbeiter aus der Infobox. (v1.6.5 Logik)
Extrahiert gezielt Branche, Umsatz oder Mitarbeiter aus der Infobox.
Berücksichtigt jetzt auch Header in <td>-Tags (z.B. <td style="font-weight:bold">).
"""
# --- DEBUG LOG: Funktion betreten ---
self.logger.debug(f"--- Entering _extract_infobox_value for target '{target}' ---")
if not soup or target not in self.keywords_map:
@@ -1761,64 +1761,75 @@ class WikipediaScraper:
keywords = self.keywords_map[target]
self.logger.debug(f"_extract_infobox_value: Suche nach '{target}' mit Keywords: {keywords}")
# Flexiblere Suche nach der Infobox
infobox = soup.select_one('table[class*="infobox"]')
# --- DEBUG LOG: Infobox gefunden? ---
if infobox:
self.logger.debug(f" -> Infobox gefunden (via select_one 'table[class*=\"infobox\"]')")
else:
if not infobox:
self.logger.debug(" -> KEINE Infobox via select_one 'table[class*=\"infobox\"]' gefunden.")
# Optional: Fallback-Suche (hier ausgelassen für Klarheit)
return "k.A." # Frühzeitiger Ausstieg
return "k.A."
self.logger.debug(f" -> Infobox gefunden (via select_one 'table[class*=\"infobox\"]')")
value_found = "k.A."
try:
rows = infobox.find_all('tr')
self.logger.debug(f" -> Analysiere {len(rows)} Zeilen in der Infobox.")
for idx, row in enumerate(rows):
# --- NEUES DETAILLIERTES LOGGING PRO ZEILE ---
self.logger.debug(f" --- Prüfe Roh-HTML Zeile {idx}: {str(row)[:150]}...") # Zeige Anfang des HTML
header_cells = row.find_all('th', recursive=False)
value_cells = row.find_all('td', recursive=False)
self.logger.debug(f" -> Zeile {idx}: Gefunden {len(header_cells)} TH Zellen, {len(value_cells)} TD Zellen (recursive=False).")
# --- ENDE NEUES LOGGING ---
self.logger.debug(f" --- Prüfe Roh-HTML Zeile {idx}: {str(row)[:150]}...")
cells = row.find_all(['th', 'td'], recursive=False) # Finde ALLE th oder td Zellen direkt unter tr
# Wir erwarten meistens ein th und ein td pro Zeile für Key-Value Paare
if len(header_cells) == 1 and len(value_cells) == 1:
header = header_cells[0]
value_cell = value_cells[0]
# --- NEUE LOGIK ZUR IDENTIFIZIERUNG VON HEADER UND WERT ---
header_text = None
value_cell = None
header_text = header.get_text(strip=True)
# --- NEUES LOGGING: Header-Text VOR Keyword-Check ---
self.logger.debug(f" -> Zeile {idx} PASST Struktur: TH Text='{header_text}'")
# --- ENDE NEUES LOGGING ---
# Fall 1: Klassisch <th> + <td>
if len(cells) == 2 and cells[0].name == 'th' and cells[1].name == 'td':
header_text = cells[0].get_text(strip=True)
value_cell = cells[1]
self.logger.debug(f" -> Zeile {idx}: Struktur TH + TD erkannt.")
# Fall 2: Header in <td> (oft mit style="font-weight:bold;") + <td>
elif len(cells) == 2 and cells[0].name == 'td' and cells[1].name == 'td':
# Prüfe, ob die erste Zelle wie ein Header aussieht (fett oder starker Text)
first_cell_is_header_like = False
style = cells[0].get('style', '').lower()
if 'font-weight' in style and ('bold' in style or '700' in style or '800' in style or '900' in style):
first_cell_is_header_like = True
# Fallback: Prüfe, ob der direkte Text fett ist (<b>, <strong>)
elif cells[0].find(['b', 'strong'], recursive=False):
first_cell_is_header_like = True
if first_cell_is_header_like:
header_text = cells[0].get_text(strip=True)
value_cell = cells[1]
self.logger.debug(f" -> Zeile {idx}: Struktur TD(Header-like) + TD erkannt.")
else:
self.logger.debug(f" -> Zeile {idx}: Struktur TD + TD, aber erstes TD nicht als Header erkannt.")
else:
self.logger.debug(f" -> Zeile {idx}: Übersprungen (Struktur passt nicht, Zellen: {len(cells)}, Typen: {[c.name for c in cells]})")
# --- ENDE NEUE LOGIK ---
# Verarbeite nur, wenn Header und Wert gefunden wurden
if header_text is not None and value_cell is not None:
self.logger.debug(f" -> Verarbeite Zeile {idx} mit Header='{header_text}'")
header_text_lower = header_text.lower()
# Normalisierte Version für flexibleren Match
header_text_normalized = re.sub(r'[\s:]', '', header_text_lower) # Nicht mehr unbedingt nötig, da wir 'in' verwenden
raw_value_preview = value_cell.get_text(strip=True)[:50]
# self.logger.debug(f" -> Prüfe Zeile {idx}: TH='{header_text}' (Norm: '{header_text_normalized}') | TD Preview='{raw_value_preview}...'") # Doppelt
matched_keyword = None
for kw in keywords:
# Prüfe ob Keyword im (nicht-normalisierten) Lowercase-Header vorkommt
if kw in header_text_lower:
matched_keyword = kw
break
if matched_keyword:
self.logger.debug(f" --> Keyword '{matched_keyword}' gefunden in TH '{header_text}'!")
self.logger.debug(f" --> Keyword '{matched_keyword}' gefunden in Header '{header_text}'!")
# Störende Elemente entfernen... (Rest der Logik bleibt gleich)
# Störende Elemente entfernen
for sup in value_cell.find_all(['sup', 'span']):
if (sup.name == 'sup' and sup.has_attr('class') and 'reference' in sup['class']) or \
(sup.name == 'span' and sup.get('style') and 'display:none' in sup['style']):
self.logger.debug(f" -> Entferne störendes Element: {sup.get_text(strip=True)}")
sup.decompose()
# Text extrahieren und bereinigen
raw_value_text = value_cell.get_text(separator=' ', strip=True)
self.logger.debug(f" -> Roher TD-Text nach Decompose: '{raw_value_text}'")
self.logger.debug(f" -> Roher TD/Value-Text nach Decompose: '{raw_value_text}'")
cleaned_raw_value = clean_text(raw_value_text)
# Spezifische Verarbeitung
@@ -1826,19 +1837,18 @@ class WikipediaScraper:
clean_val = re.sub(r'\s*\([^)]*\)', '', cleaned_raw_value).strip()
clean_val = clean_val.split('\n')[0].strip()
value_found = clean_val if clean_val else "k.A."
self.logger.debug(f" --> Branche extrahiert: '{value_found}'")
self.logger.info(f" --> Branche extrahiert: '{value_found}'") # INFO statt DEBUG für gefundene Werte
elif target == 'umsatz':
numeric_val = extract_numeric_value(cleaned_raw_value, is_umsatz=True)
value_found = numeric_val
self.logger.debug(f" --> Umsatz extrahiert (aus '{cleaned_raw_value}'): '{value_found}'")
self.logger.info(f" --> Umsatz extrahiert (aus '{cleaned_raw_value}'): '{value_found}'")
elif target == 'mitarbeiter':
numeric_val = extract_numeric_value(cleaned_raw_value, is_umsatz=False)
value_found = numeric_val
self.logger.debug(f" --> Mitarbeiter extrahiert (aus '{cleaned_raw_value}'): '{value_found}'")
self.logger.info(f" --> Mitarbeiter extrahiert (aus '{cleaned_raw_value}'): '{value_found}'")
break # Ersten Treffer nehmen
# else: # Optional: Logge Zeilen, die übersprungen werden
# self.logger.debug(f" -> Zeile {idx}: Übersprungen (Struktur nicht 1 TH / 1 TD).")
# WICHTIG: Schleife für dieses Ziel beenden, da Wert gefunden wurde
break
# Ende der Zeilenschleife
if value_found != "k.A.":