Skip to content

Commit b5778f9

Browse files
committed
fix(lubimyczytac): restore search results and detail-page metadata
LubimyCzytac.pl restructured its markup, which broke the provider in four places: - Search results moved from `authorAllBooks__single` to `book-card--l`, so `parse_search_results()` matched nothing and every query returned zero results. - The publisher moved out of the `<dl>` definition list into a `span.book__txt` element, so `publisher` was always None. - The description moved from `div.collapse-content` to `#book-description`, so `_parse_description()` silently fell back to the truncated `og:description` meta tag. - The book page now emits an `Organization` ld+json block before the `Book` one, and `_parse_from_summary()` only read the first block, so `publishedDate` was always None. Verified against live HTML for 9 search queries and 14 book pages: queries returning matches 0/9 -> 9/9, publisher 0/14 -> 14/14, publishedDate 0/14 -> 14/14, description 0/14 -> 14/14 (3.1x more text than the meta-tag fallback across 18 end-to-end results).
1 parent 43718d8 commit b5778f9

1 file changed

Lines changed: 25 additions & 10 deletions

File tree

cps/metadata_provider/lubimyczytac.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,26 @@ class LubimyCzytac(Metadata):
7373
BASE_URL = "https://lubimyczytac.pl"
7474

7575
BOOK_SEARCH_RESULT_XPATH = (
76-
"*//div[@class='listSearch']//div[@class='authorAllBooks__single']"
76+
"*//div[@class='listSearch']//div[contains(@class,'book-card--l')]"
7777
)
78-
SINGLE_BOOK_RESULT_XPATH = ".//div[contains(@class,'authorAllBooks__singleText')]"
79-
TITLE_PATH = "/div/a[contains(@class,'authorAllBooks__singleTextTitle')]"
78+
SINGLE_BOOK_RESULT_XPATH = ".//div[contains(@class,'book-card__info-box')]"
79+
TITLE_PATH = "/a[contains(@class,'book-card__title')]"
8080
TITLE_TEXT_PATH = f"{TITLE_PATH}//text()"
8181
URL_PATH = f"{TITLE_PATH}/@href"
82-
AUTHORS_PATH = "/div/a[contains(@href,'autor')]//text()"
82+
AUTHORS_PATH = "/div[contains(@class,'book-card__author')]/a//text()"
8383

8484
SIBLINGS = "/following-sibling::dd"
8585

8686
CONTAINER = "//section[@class='container book']"
87-
PUBLISHER = f"{CONTAINER}//dt[contains(text(),'Wydawnictwo:')]{SIBLINGS}/a/text()"
87+
PUBLISHER = (
88+
f"{CONTAINER}//span[contains(@class,'book__txt')]"
89+
"[contains(text(),'Wydawnictwo:')]/a/text()"
90+
)
8891
LANGUAGES = f"{CONTAINER}//dt[contains(text(),'Język:')]{SIBLINGS}/text()"
89-
DESCRIPTION = f"{CONTAINER}//div[@class='collapse-content']"
92+
DESCRIPTION = (
93+
f"{CONTAINER}//*[@id='book-description']"
94+
f" | {CONTAINER}//div[contains(@class,'book__description')]"
95+
)
9096
SERIES = f"{CONTAINER}//span/a[contains(@href,'/cykl/')]/text()"
9197
TRANSLATOR = f"{CONTAINER}//dt[contains(text(),'Tłumacz:')]{SIBLINGS}/a/text()"
9298

@@ -288,11 +294,20 @@ def _parse_tags(self) -> List[str]:
288294
return []
289295

290296
def _parse_from_summary(self, attribute_name: str) -> Optional[str]:
297+
# The page emits several ld+json blocks (Organization, Book, ...),
298+
# so pick the Book one instead of blindly taking the first.
291299
value = None
292-
summary_text = self._parse_xpath_node(xpath=LubimyCzytac.SUMMARY)
293-
if summary_text:
294-
data = json.loads(summary_text)
295-
value = data.get(attribute_name)
300+
summary_texts = self._parse_xpath_node(
301+
xpath=LubimyCzytac.SUMMARY, take_first=False
302+
)
303+
for summary_text in summary_texts or []:
304+
try:
305+
data = json.loads(summary_text)
306+
except ValueError:
307+
continue
308+
if isinstance(data, dict) and data.get("@type") == "Book":
309+
value = data.get(attribute_name)
310+
break
296311
return value.strip() if value is not None else value
297312

298313
def _parse_rating(self) -> Optional[str]:

0 commit comments

Comments
 (0)