feat(parsers): CyberLeninka full_text из OCR-фрагментов поиска (без доп. запросов)
Поисковый API КиберЛенинки отдаёт поле "ocr" — список OCR-фрагментов текста статьи (начало + фрагмент с ключевыми словами), прямо в ответе search. Раньше transform() игнорировал его (full_text всегда None), и Winnowing-отпечатки (L1) считались только по короткой annotation (~150 симв.) либо не считались вовсе, если аннотации не было. Теперь ocr (список) склеивается, чистится (<b>/сущности) и идёт в full_text — add_document уже умеет: `text = full_text or abstract`. Даёт заметно более точные L1-отпечатки для ВСЕХ будущих CyberLeninka-документов бесплатно — 0 доп. HTTP- запросов, работает и там, где annotation вообще пустая (проверено вживую). 2 новых теста (ocr→full_text, отсутствие ocr→None). Тестов в файле: 7. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,13 @@ class CyberLeninkaParser(BaseParser):
|
|||||||
link = raw.get("link", "")
|
link = raw.get("link", "")
|
||||||
url = f"{BASE_URL}{link}" if link.startswith("/") else link or None
|
url = f"{BASE_URL}{link}" if link.startswith("/") else link or None
|
||||||
|
|
||||||
|
# OCR-фрагменты текста статьи — приходят прямо в ответе поиска (список
|
||||||
|
# кусков, обычно начало статьи + фрагмент с ключевыми словами), без
|
||||||
|
# доп. запроса. Не полный текст всей статьи, но заметно богаче аннотации —
|
||||||
|
# используем как full_text для более точных Winnowing-отпечатков (L1).
|
||||||
|
ocr = raw.get("ocr")
|
||||||
|
full_text = _clean(" ".join(ocr)) if isinstance(ocr, list) and ocr else None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"source": self.source_name,
|
"source": self.source_name,
|
||||||
"ext_id": ext_id,
|
"ext_id": ext_id,
|
||||||
@@ -151,7 +158,7 @@ class CyberLeninkaParser(BaseParser):
|
|||||||
"pages": raw.get("pages") or None,
|
"pages": raw.get("pages") or None,
|
||||||
"abstract": _clean(raw.get("annotation")) or None,
|
"abstract": _clean(raw.get("annotation")) or None,
|
||||||
"url": url,
|
"url": url,
|
||||||
"full_text": None,
|
"full_text": full_text,
|
||||||
}
|
}
|
||||||
|
|
||||||
def fetch_article_details(self, url: str) -> dict[str, Any]:
|
def fetch_article_details(self, url: str) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -51,3 +51,14 @@ def test_transform_handles_string_authors():
|
|||||||
|
|
||||||
def test_transform_empty_without_id_or_link():
|
def test_transform_empty_without_id_or_link():
|
||||||
assert CyberLeninkaParser().transform({"name": "x"}) == {}
|
assert CyberLeninkaParser().transform({"name": "x"}) == {}
|
||||||
|
|
||||||
|
|
||||||
|
def test_transform_uses_ocr_as_full_text():
|
||||||
|
raw = dict(SAMPLE, ocr=["Первый <b>фрагмент</b> статьи.", "Второй & фрагмент."])
|
||||||
|
t = CyberLeninkaParser().transform(raw)
|
||||||
|
assert t["full_text"] == "Первый фрагмент статьи. Второй & фрагмент."
|
||||||
|
|
||||||
|
|
||||||
|
def test_transform_full_text_none_without_ocr():
|
||||||
|
assert CyberLeninkaParser().transform(SAMPLE)["full_text"] is None
|
||||||
|
assert CyberLeninkaParser().transform(dict(SAMPLE, ocr=[]))["full_text"] is None
|
||||||
|
|||||||
Reference in New Issue
Block a user