Skip to content

Commit 8eb1488

Browse files
authored
Merge pull request #787 from flairNLP/fix-golem
Fix ˋGolemˋ
2 parents 4b66177 + 38ded5f commit 8eb1488

File tree

5 files changed

+122
-8
lines changed

5 files changed

+122
-8
lines changed

src/fundus/parser/utility.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,17 @@ class Node:
7676
# one could replace this recursion with XPath using an expression like this:
7777
# //*[not(self::script) and text()]/text(), but for whatever reason, that's actually 50-150% slower
7878
# than simply using the implemented mixture below
79-
def text_content(self, excluded_tags: Optional[List[str]] = None) -> str:
79+
def text_content(self, excluded_tags: Optional[List[str]] = None, tag_filter: Optional[XPath] = None) -> str:
8080
guarded_excluded_tags: List[str] = excluded_tags or []
8181

8282
def _text_content(element: lxml.html.HtmlElement) -> str:
83-
if element.tag in guarded_excluded_tags:
83+
if (
84+
element.tag in guarded_excluded_tags
85+
or isinstance(element, lxml.html.HtmlComment)
86+
or (tag_filter and tag_filter(element))
87+
):
8488
return element.tail or ""
85-
text = element.text or "" if not isinstance(element, lxml.html.HtmlComment) else ""
89+
text = element.text or ""
8690
children = "".join([_text_content(child) for child in element.iterchildren()])
8791
tail = element.tail or ""
8892
return text + children + tail
@@ -133,6 +137,7 @@ def extract_article_body_with_selector(
133137
paragraph_selector: XPath,
134138
summary_selector: Optional[XPath] = None,
135139
subheadline_selector: Optional[XPath] = None,
140+
tag_filter: Optional[XPath] = None,
136141
) -> ArticleBody:
137142
# depth first index for each element in tree
138143
df_idx_by_ref = {element: i for i, element in enumerate(doc.iter())}
@@ -164,14 +169,22 @@ def extract_nodes(selector: XPath, node_type: Type[Node]) -> List[Node]:
164169
instructions = itertools.chain([first, []], instructions)
165170

166171
summary = TextSequence(
167-
map(lambda x: normalize_whitespace(x.text_content(excluded_tags=["script"])), next(instructions))
172+
map(
173+
lambda x: normalize_whitespace(x.text_content(excluded_tags=["script"], tag_filter=tag_filter)),
174+
next(instructions),
175+
)
168176
)
169177
sections: List[ArticleSection] = []
170178

171179
for chunk in more_itertools.chunked(instructions, 2):
172180
if len(chunk) == 1:
173181
chunk.append([])
174-
texts = [list(map(lambda x: normalize_whitespace(x.text_content(excluded_tags=["script"])), c)) for c in chunk]
182+
texts = [
183+
list(
184+
map(lambda x: normalize_whitespace(x.text_content(excluded_tags=["script"], tag_filter=tag_filter)), c)
185+
)
186+
for c in chunk
187+
]
175188
sections.append(ArticleSection(*map(TextSequence, texts)))
176189

177190
return ArticleBody(summary=summary, sections=sections)

src/fundus/publishers/de/golem.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import datetime
22
import re
3-
from typing import List, Optional
3+
from typing import List, Optional, Union
44

55
from lxml.cssselect import CSSSelector
66
from lxml.etree import XPath
77

88
from fundus.parser import ArticleBody, BaseParser, Image, ParserProxy, attribute
9+
from fundus.parser.data import TextSequence
910
from fundus.parser.utility import (
1011
extract_article_body_with_selector,
1112
generic_author_parsing,
@@ -17,13 +18,15 @@
1718

1819
class GolemParser(ParserProxy):
1920
class V1(BaseParser):
21+
VALID_UNTIL = datetime.date(2025, 8, 21)
22+
2023
_bloat_regex = r"^Dieser Artikel enthält sogenannte Affiliate-Links"
21-
_summary_selector = CSSSelector("hgroup > p")
24+
_summary_selector = XPath("//hgroup/p")
2225
_paragraph_selector = XPath(
2326
f"//section /p[not(@class='meta' or re:test(string(), '{_bloat_regex}'))]",
2427
namespaces={"re": "http://exslt.org/regular-expressions"},
2528
)
26-
_subheadline_selector = CSSSelector("div > section > h2")
29+
_subheadline_selector: Union[XPath, CSSSelector] = CSSSelector("div > section > h2")
2730

2831
@attribute
2932
def body(self) -> Optional[ArticleBody]:
@@ -32,6 +35,7 @@ def body(self) -> Optional[ArticleBody]:
3235
summary_selector=self._summary_selector,
3336
paragraph_selector=self._paragraph_selector,
3437
subheadline_selector=self._subheadline_selector,
38+
tag_filter=XPath("self::*[@class='go-vh']"),
3539
)
3640

3741
@attribute
@@ -61,3 +65,10 @@ def images(self) -> List[Image]:
6165
upper_boundary_selector=XPath("//article"),
6266
author_selector=re.compile(r"(?i)\(bild:(?P<credits>.*)\)"),
6367
)
68+
69+
class V1_1(V1):
70+
VALID_UNTIL = datetime.date.today()
71+
72+
_paragraph_selector = XPath("//article//p[not(ancestor::div[@class='go-info-box__content'])]")
73+
_subheadline_selector = XPath("//article//h2[not(contains(@class, 'teaser'))]")
74+
_summary_selector = XPath("//div[@class='go-article-header__intro']")

tests/resources/parser/test_data/de/Golem.json

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,91 @@
6464
"Wirtschaft",
6565
"Mobil"
6666
]
67+
},
68+
"V1_1": {
69+
"authors": [
70+
"Frank Wunderlich-Pfeiffer"
71+
],
72+
"body": {
73+
"summary": [
74+
"VW hat den Prototyp eines Quantumscape-Akkupacks für eine Ducati V21L vorgestellt. Unklar ist, ob dafür genug Akkus geliefert wurden."
75+
],
76+
"sections": [
77+
{
78+
"headline": [],
79+
"paragraphs": [
80+
"Volkswagen hat den Prototyp eines Akkupacks für ein modifiziertes Ducati V21L Rennmotorad vorgestellt und dabei fast keine technischen Daten genannt. Es soll \"bis zu\" 980 QSE-5-Akkuzellen von Quantumscape enthalten können; mehr war von Volkswagen nicht zu erfahren . Auch Quantumscape äußerte sich nicht zu weiteren Daten des Akkupacks. Deren Pressemitteilung nannte lediglich die Energiedichte der Zellen von 844 Wh/l mit einer Entladerate von 10C und einer Laderate von 3,5C, verschwieg aber deren gravimetrische Dichte von 301 Wh/kg.",
81+
"Zum eigentlichen Akkupack und dessen Leistung wurden keine weiteren Angaben gemacht. Die reguläre Ducati V21L nutzt die von Tesla bekannten zylindrischen Zellen im 2170-Format und erreichte damit eine Kapazität von 18 kWh. Das neue Pack würde mit 980 Zellen eine Kapazität von rund 21 kWh erreichen, bei Zimmertemperatur und ohne jede Reserve. Es gebe jedoch keinen Anlass, lediglich \"bis zu 980 Zellen\" zu schreiben, wenn sich tatsächlich 980 Akkuzellen in dem Akkupack befänden, zumal das Motorrad und das Akkupack lediglich auf einer Bühne standen.",
82+
"Entweder gibt es noch ungelöste Probleme mit Mechanik und Kühlung des Akkupacks – oder es gibt noch nicht genug Akkuzellen. Aber die Ingenieure von Ducati dürften ausreichend Erfahrung im Entwurf von Akkupacks haben. Laut Quantumscape soll der Cobra-Separator-Produktionsprozess für die QSE-5-Zellen seit Juni 2025 in Betrieb sein. Die Firma erweckt nun jedoch den Eindruck, dass es ihr nicht gelang, innerhalb von 3 Monaten rund 1.000 funktionierende Zellen für Volkswagen, den Hauptkunden und größten Investor von Quantumscape, zu produzieren."
83+
]
84+
},
85+
{
86+
"headline": [
87+
"Quantumscape versprach 2020 eine Revolution"
88+
],
89+
"paragraphs": [
90+
"Vor fünf Jahren, im September 2020, versprach Quantumscape noch vor dem Börsengang ihren Investoren , zu denen Volkswagen auch schon gehörte, einen revolutionären Akku zu entwickeln. Er sollte eine Energiedichte von 400 bis 500 Wh/kg und 1.000 Wh/l erreichen. Nur damit sollte Elektromobilität auf dem Massenmarkt überhaupt möglich sein, wie später im Dezember vollmundig beim Börsengang behauptet wurde.",
91+
"Etwa zur gleichen Zeit nutzte Tesla Akkus von Panasonic mit 271 Wh/kg und 755 Wh/l, und chinesische Firmen lieferten neue Autos mit LFP-Akkus aus, deren Zellen zwar nur rund 180 Wh/kg und 380 Wh/l hatten, aber Elektroautos nicht nur in China massentauglich machten.",
92+
"Nach damaligen Aussagen war die Technik fast bereit für die Massenproduktion. Spätestens 2022 sollte die erste Fabrik mit 1 GWh Produktionskapazität gebaut werden und 2023 die Produktion aufnehmen. Für 2023 war die Produktion von 250 MWh geplant, was mehr als 10 Millionen QSE-5-Zellen entspricht. In der zweiten Jahreshälfte 2025, also heute, sollte die Fabrik auf bis zu 20 GWh Kapazität erweitert werden und 5 GWh im Jahr 2026 produzieren.",
93+
"In der Realität kann im September 2025 nicht einmal mit Sicherheit gesagt werden, dass Quantumscape Akkuzellen mit insgesamt 0,000021 GWh an deren wichtigsten Kunden liefern konnte. Ihre Energiedichte ist mit 301 Wh/kg schon im Vergleich zu Akkus aus dem Jahr 2021 nur wenig beeindruckend, keineswegs revolutionär und weit entfernt von Konkurrenten, die bereits tatsächlich Zellen mit 400 bis 500 Wh/kg demonstriert haben."
94+
]
95+
},
96+
{
97+
"headline": [
98+
"Quantumscape baut keine Festkörperakkus"
99+
],
100+
"paragraphs": [
101+
"Zuletzt muss auch angemerkt werden, dass es sich bei den Akkus von Quantumscape – entgegen der Aufschrift auf dem Motorrad – nicht um Festkörperakkus handelt. Lediglich der Separator ist eine Keramik, nicht jedoch der Elektrolyt der Kathode. Die Kathode benutzt weiterhin einen brennbaren Elektrolyt aus Kohlenwasserstoffen, der ab einer bestimmten Temperatur ohne ausreichende Kühlung zur Selbsterhitzung und anschließender Entzündung des Akkus führen wird.",
102+
"Dieser Prozess beginnt, wenn das Kathodenmaterial ab einer kritischen Temperatur beginnt, sich zu zersetzen und dabei Sauerstoff freisetzt. Die genaue Temperatur hängt vom verwendeten Kathodenmaterial und dem Ladezustand ab. Mit dem wahrscheinlich verwendeten NMC811 wird eine Selbsterwärmung im Labor bereits bei 100 Grad Celsius beobachtet, die sich ab 180 Grad Celsius stark beschleunigt."
103+
]
104+
}
105+
]
106+
},
107+
"images": [
108+
{
109+
"versions": [
110+
{
111+
"url": "https://www.golem.de/2509/199920-532846-532845_rc.jpg",
112+
"query_width": null,
113+
"size": null,
114+
"type": "image/jpeg"
115+
}
116+
],
117+
"is_cover": true,
118+
"description": "Ein Motorrad mit der englischen Aufschrift für \"Festkörperakku\" (Bild: VW)",
119+
"caption": "Ein Motorrad mit der englischen Aufschrift für \"Festkörperakku\" VW",
120+
"authors": [
121+
"VW"
122+
],
123+
"position": 344
124+
},
125+
{
126+
"versions": [
127+
{
128+
"url": "https://video.golem.de/teaser/1/1/25365/medium-480-qscape-snap.jpg",
129+
"query_width": null,
130+
"size": null,
131+
"type": "image/jpeg"
132+
}
133+
],
134+
"is_cover": false,
135+
"description": "Quantumscape – Präsentation",
136+
"caption": "Quantumscape – Präsentation (1:24:10)",
137+
"authors": [],
138+
"position": 470
139+
}
140+
],
141+
"publishing_date": "2025-09-09 13:46:01+00:00",
142+
"title": "Akkutechnik: Hat Quantumscape genug Akkus für ein Motorrad gebaut?",
143+
"topics": [
144+
"Wissen",
145+
"Innovation & Forschung",
146+
"Mobilität",
147+
"Auto",
148+
"Nachhaltigkeit",
149+
"Akku",
150+
"VW",
151+
"Elektromobilität"
152+
]
67153
}
68154
}
101 KB
Binary file not shown.

tests/resources/parser/test_data/de/meta.info

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107
"url": "https://www.golem.de/news/lte-patent-samsung-soll-wegen-patentklage-smartphones-zerstoeren-2404-184627.html",
108108
"crawl_date": "2024-04-28 20:12:24.192464"
109109
},
110+
"Golem_2025_09_09.html.gz": {
111+
"url": "https://www.golem.de/news/akkutechnik-hat-quantumscape-genug-akkus-fuer-ein-motorrad-gebaut-2509-199920.html",
112+
"crawl_date": "2025-09-09 17:44:53.235821"
113+
},
110114
"HamburgerAbendblatt_2024_04_28.html.gz": {
111115
"url": "https://www.abendblatt.de/hamburg/article242192802/Hamburg-Marathon-2024-Royaler-Besuch-auf-der-Laufstrecke-1.html",
112116
"crawl_date": "2024-04-28 17:22:58.422635"

0 commit comments

Comments
 (0)