From ced9c3f7230faf448bfdd2e40ef92ed02102d908 Mon Sep 17 00:00:00 2001 From: Floke Date: Sat, 19 Apr 2025 17:49:33 +0000 Subject: [PATCH] bugfix --- brancheneinstufung.py | 86 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 6f1e6188..5401403b 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -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 -Tags (z.B. ). """ - # --- 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 + + 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 (oft mit style="font-weight:bold;") + + 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 (, ) + 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.":