feat: add RF4DB and RF4-STAT research parsers
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
<main>
|
||||
<article class="catch-card"><div class="catch-card__body"><div class="catch-card__main">
|
||||
<h2><a href="/ru/fishes/pike">Щука обыкновенная</a></h2>
|
||||
<p class="catch-card__place"><span><a href="/ru/maps/test-lake">Тестовое озеро</a></span> · <b>71:92</b> · <small>Игровое время 06:14</small> · <small>Наживка <a href="/ru/wiki/baits/test-lure">Тестовая приманка</a></small></p>
|
||||
<div class="catch-card__badges"><span class="catch-badge">Погода <b>Ясно</b></span><span class="catch-badge">Темп. воды <b>12.5°C</b></span><span class="catch-badge catch-badge--rig">Искусственная приманка</span></div>
|
||||
</div><a class="catch-card__time" href="/ru/catches/11111111-1111-4111-8111-111111111111"><time><strong>Недавно</strong></time></a></div></div></article>
|
||||
</main>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<article class="catch-detail shell"><div class="catch-detail__body">
|
||||
<dl class="catch-facts">
|
||||
<div><dt>Ветер</dt><dd>SE 4 м/с</dd></div>
|
||||
<div><dt>Выпуск лески</dt><dd>5.1 m</dd></div>
|
||||
<div><dt>Клипса</dt><dd>5 m</dd></div>
|
||||
<div><dt>Направление заброса</dt><dd>181.1°</dd></div>
|
||||
</dl>
|
||||
<div class="catch-equipment">
|
||||
<article><div><small>Приманка поклёвки</small><a href="/ru/wiki/baits/test-lure">Тестовая приманка</a></div></article>
|
||||
<article><div><small>Катушка</small><a href="/ru/wiki/reels/test-reel">Тестовая катушка</a></div></article>
|
||||
</div>
|
||||
</div></article>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<table><tr class="load-row"><td class="time"><a class="share" href="fishing/123">#123</a><a class="share hide-print" href="fishing/123.png">image</a><div>11:27</div><small>03.09</small></td><td class="mobile-location">Тестовое озеро</td><td class="fish-icon"><a href="fish/pike">fish</a></td><td class="fish"><a data-filter="fish">Щука</a><small>11 584 г</small></td><td><a data-filter="bait">Тестовая приманка</a></td><td class="list-gamer"><a>Игрок</a></td><td class="list-position"><span class="position">71:92</span><span class="clip">35</span><img class="post-style-icon" title="Вид ловли: Донная"/></td></tr></table>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<div class="post-item load-row" data-post-id="456" data-published-at="1788434956"><div class="location">Тестовое озеро</div><div class="spot-col"><span class="position position-locked">XX:XX</span><span class="clip">25</span><img class="post-style-icon" title="Вид ловли: Спиннинг"/></div><div class="fish-icon"><a href="fish/pike">fish</a><small class="weight">4 321 г</small><div class="fish-name">Щука</div></div><div class="bait-text">Тестовая приманка</div><div class="player">Игрок</div><div class="screen-file-slot"><img src="https://img.example.test/proof.jpg"/></div></div>
|
||||
@@ -0,0 +1,75 @@
|
||||
from datetime import datetime, time, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from rf4_research.community_sources import (
|
||||
CommunityParseError,
|
||||
parse_rf4db_catches,
|
||||
parse_rf4db_detail,
|
||||
parse_rf4stat_fishing,
|
||||
parse_rf4stat_posts,
|
||||
)
|
||||
|
||||
|
||||
FIXTURES = Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
def fixture(name: str) -> str:
|
||||
return (FIXTURES / name).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_parses_rf4db_public_catch_cards() -> None:
|
||||
row = parse_rf4db_catches(fixture("rf4db_catches_sample.html"))[0]
|
||||
|
||||
assert (row.source_system, row.source_external_id) == ("rf4db", "11111111-1111-4111-8111-111111111111")
|
||||
assert (row.fish, row.fish_external_id) == ("Щука обыкновенная", "pike")
|
||||
assert (row.waterbody, row.waterbody_external_id) == ("Тестовое озеро", "test-lake")
|
||||
assert (row.x, row.y, row.weight_g) == (71, 92, None)
|
||||
assert row.game_time == time(6, 14)
|
||||
assert row.water_temperature_c == 12.5
|
||||
|
||||
|
||||
def test_parses_rf4db_detail_equipment_and_cast_facts() -> None:
|
||||
detail = parse_rf4db_detail(
|
||||
fixture("rf4db_detail_sample.html"),
|
||||
source_url="https://rf4db.com/ru/catches/11111111-1111-4111-8111-111111111111",
|
||||
)
|
||||
|
||||
assert detail.source_external_id == "11111111-1111-4111-8111-111111111111"
|
||||
assert (detail.wind, detail.line_release_m, detail.clip_m, detail.cast_direction_deg) == ("SE 4 м/с", 5.1, 5.0, 181.1)
|
||||
assert [(item.kind, item.name, item.external_id) for item in detail.equipment] == [
|
||||
("Приманка поклёвки", "Тестовая приманка", "test-lure"),
|
||||
("Катушка", "Тестовая катушка", "test-reel"),
|
||||
]
|
||||
|
||||
|
||||
def test_rf4db_detail_rejects_unrelated_html() -> None:
|
||||
with pytest.raises(CommunityParseError, match="detail not found"):
|
||||
parse_rf4db_detail("<html></html>", source_url="https://rf4db.com/ru/catches/id")
|
||||
|
||||
|
||||
def test_parses_rf4stat_fishing_rows() -> None:
|
||||
row = parse_rf4stat_fishing(
|
||||
fixture("rf4stat_fishing_sample.html"),
|
||||
now=datetime(2026, 9, 3, 12, tzinfo=timezone.utc),
|
||||
)[0]
|
||||
|
||||
assert (row.source_system, row.source_external_id) == ("rf4stat-fishing", "123")
|
||||
assert (row.x, row.y, row.weight_g) == (71, 92, 11_584)
|
||||
assert row.published_at == datetime(2026, 9, 3, 11, 27, tzinfo=timezone.utc)
|
||||
assert (row.player_name, row.clip, row.fishing_style) == ("Игрок", "35", "Донная")
|
||||
|
||||
|
||||
def test_parses_rf4stat_posts_without_using_locked_coordinates() -> None:
|
||||
row = parse_rf4stat_posts(fixture("rf4stat_posts_sample.html"))[0]
|
||||
|
||||
assert (row.source_system, row.source_external_id) == ("rf4stat-post", "456:0")
|
||||
assert (row.x, row.y, row.weight_g) == (None, None, 4_321)
|
||||
assert row.evidence_urls == ("https://img.example.test/proof.jpg",)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("parser", [parse_rf4db_catches, parse_rf4stat_fishing, parse_rf4stat_posts])
|
||||
def test_parsers_reject_unrelated_html(parser) -> None:
|
||||
with pytest.raises(CommunityParseError):
|
||||
parser("<html><body>not a source page</body></html>")
|
||||
Reference in New Issue
Block a user