Поисковый 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>
65 lines
2.7 KiB
Python
65 lines
2.7 KiB
Python
"""Юнит-тесты парсера CyberLeninka — чистая логика transform (без сети).
|
||
|
||
Стерегут исправления реальных багов: JSON-API отдаёт authors списком, а name/
|
||
annotation — с HTML-подсветкой (<b>) и сущностями (").
|
||
"""
|
||
|
||
from cyberleninka import CyberLeninkaParser, _authors_from_list, _clean
|
||
|
||
# Форма ответа POST /api/search КиберЛенинки
|
||
SAMPLE = {
|
||
"name": "СОДЕРЖАНИЕ <b>ЭКОНОМИЧЕСКОГО</b> <b>АНАЛИЗА</b> "X"",
|
||
"annotation": "В статье <b>рассматривается</b> вопрос",
|
||
"authors": ["Вишникина А. Д.", "Клопова А. А."],
|
||
"journal": "Экономика и социум",
|
||
"year": 2024,
|
||
"link": "/article/n/soderzhanie",
|
||
}
|
||
|
||
|
||
def test_clean_strips_tags_and_entities():
|
||
assert _clean('<b>Тест</b> "X"') == 'Тест "X"'
|
||
assert _clean(None) == ""
|
||
assert _clean(" чисто ") == "чисто"
|
||
|
||
|
||
def test_authors_from_list():
|
||
a = _authors_from_list(["Вишникина А. Д.", "Иванов И."])
|
||
assert a[0] == {"last_name": "Вишникина", "initials": "А. Д."}
|
||
assert a[1] == {"last_name": "Иванов", "initials": "И."}
|
||
assert _authors_from_list([]) == []
|
||
|
||
|
||
def test_transform_cleans_and_maps_fields():
|
||
t = CyberLeninkaParser().transform(SAMPLE)
|
||
assert "<b>" not in t["title"] and """ not in t["title"]
|
||
assert t["title"].startswith("СОДЕРЖАНИЕ ЭКОНОМИЧЕСКОГО АНАЛИЗА")
|
||
assert t["lang"] == "ru"
|
||
assert t["year"] == 2024
|
||
assert t["journal"] == "Экономика и социум"
|
||
assert t["url"] == "https://cyberleninka.ru/article/n/soderzhanie"
|
||
assert t["source"] == "cyberleninka"
|
||
assert t["authors"][0]["last_name"] == "Вишникина"
|
||
assert "<b>" not in t["abstract"]
|
||
|
||
|
||
def test_transform_handles_string_authors():
|
||
raw = dict(SAMPLE, authors="Иванов И.И., Петров П.П.")
|
||
t = CyberLeninkaParser().transform(raw)
|
||
assert len(t["authors"]) == 2
|
||
|
||
|
||
def test_transform_empty_without_id_or_link():
|
||
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
|