Use Russian transport

This commit is contained in:
qananasikq
2026-08-18 13:10:47 +03:00
parent 8196fe50d2
commit e6c6732ed8
4 changed files with 223 additions and 35 deletions
+81
View File
@@ -434,6 +434,87 @@ class TestMobileDeMapper(unittest.TestCase):
self.assertEqual(record.drive, "FWD")
def test_russian_search_values_map_to_english_contract(self) -> None:
record = self.mapper.listing_to_car_record(
MobileDeListing(
id="2001",
url="https://suchen.mobile.de/fahrzeuge/details.html?id=2001&lang=en",
title="Audi e-tron quattro",
raw={
"make": {"localized": "Audi"},
"model": {"localized": "e-tron"},
"price": {"grs": {"amount": 29700}},
"hasDamage": "false",
"isNew": "false",
"attr": {
"fr": "05/2021",
"ml": "59 000 км",
"ecol": "Черный Металлик",
"tr": "Автоматическая",
"c": "Внедорожник/Пикап",
},
},
)
)
self.assertEqual(record.brand, "Audi")
self.assertEqual(record.model, "e-tron")
self.assertEqual(record.year, 2021)
self.assertEqual(record.price, 29700)
self.assertEqual(record.mileage, 59000)
self.assertEqual(record.color, "black")
self.assertEqual(record.gearbox, "AT")
self.assertEqual(record.drive, "4WD")
self.assertEqual(record.body_type, "SUV")
self.assertFalse(record.is_damaged)
self.assertFalse(record.new_car)
def test_russian_detail_values_and_exact_gallery_map_to_english_contract(self) -> None:
first = "img.classistatic.de/api/v1/mo-prod/images/a1/a1111111-1111-4111-8111-111111111111"
second = "img.classistatic.de/api/v1/mo-prod/images/b2/b2222222-2222-4222-8222-222222222222"
unrelated = "img.classistatic.de/api/v1/mo-prod/images/c3/c3333333-3333-4333-8333-333333333333"
record = self.mapper.detail_to_car_record(
"2002",
{
"shortTitle": "Porsche Macan",
"subTitle": "GTS",
"make": {"localized": "Porsche"},
"model": {"localized": "Macan"},
"price": {"grs": {"amount": 59900, "currency": "EUR"}},
"isConditionNew": "false",
"attributes": [
{"tag": "firstRegistration", "value": "04/2022"},
{"tag": "mileage", "value": "149 300 км"},
{"tag": "color", "value": "Синий Металлик"},
{"tag": "transmission", "value": "Автоматическая"},
{"tag": "category", "value": "Внедорожник/Пикап"},
{"tag": "cubicCapacity", "value": "2 894 ccm"},
{"tag": "numberOfPreviousOwners", "value": "1"},
{"tag": "damageCondition", "value": "Подержанный, Устраненные повреждения после ДТП"},
],
"images": [{"uri": first}, {"uri": second}],
"links": {"preview": unrelated},
},
)
self.assertEqual(record.year, 2022)
self.assertEqual(record.mileage, 149300)
self.assertEqual(record.color, "blue")
self.assertEqual(record.gearbox, "AT")
self.assertEqual(record.body_type, "SUV")
self.assertEqual(record.engine_volume, 2894)
self.assertTrue(record.one_owner)
self.assertTrue(record.is_damaged)
self.assertFalse(record.new_car)
self.assertEqual(len(record.images), 2)
self.assertEqual(
[image.fullres_image for image in record.images],
[
f"https://{first}?rule=mo-1600",
f"https://{second}?rule=mo-1600",
],
)
if __name__ == "__main__":
unittest.main()
+17 -11
View File
@@ -47,20 +47,24 @@ class _Persistence:
class TestMobileDeRequirements(unittest.TestCase):
def test_english_urls_and_header_preserve_existing_query(self) -> None:
def test_russian_transport_and_english_public_url_preserve_query(self) -> None:
search = MobileDeClient.build_search_url_from_existing(
"https://www.mobile.de/ru/search.html?ms=3500&lang=de&custom=keep",
"https://suchen.mobile.de/fahrzeuge/search.html?ms=3500&lang=en&custom=keep",
page_number=3,
)
detail = MobileDeClient.build_detail_url("123")
self.assertEqual(DEFAULT_HEADERS["accept-language"], "en-US,en;q=0.9")
transport_detail = MobileDeClient.build_transport_detail_url("123")
public_detail = MobileDeClient.build_detail_url("123")
self.assertEqual(DEFAULT_HEADERS["accept-language"], "ru-RU,ru;q=0.9,de;q=0.8,en;q=0.7")
self.assertEqual(urlsplit(search).scheme, "https")
self.assertEqual(urlsplit(search).netloc, "suchen.mobile.de")
self.assertEqual(urlsplit(search).path, "/fahrzeuge/search.html")
self.assertEqual(urlsplit(detail).path, "/fahrzeuge/details.html")
self.assertEqual(parse_qs(urlsplit(search).query)["lang"], ["en"])
self.assertEqual(urlsplit(search).netloc, "www.mobile.de")
self.assertEqual(urlsplit(search).path, "/ru/транспортные-средства/поиск.html")
self.assertEqual(urlsplit(transport_detail).path, "/ru/транспортные-средства/подробности.html")
self.assertEqual(urlsplit(public_detail).netloc, "suchen.mobile.de")
self.assertEqual(urlsplit(public_detail).path, "/fahrzeuge/details.html")
self.assertEqual(parse_qs(urlsplit(search).query)["lang"], ["ru"])
self.assertEqual(parse_qs(urlsplit(search).query)["custom"], ["keep"])
self.assertEqual(parse_qs(urlsplit(detail).query)["lang"], ["en"])
self.assertEqual(parse_qs(urlsplit(transport_detail).query)["lang"], ["ru"])
self.assertEqual(parse_qs(urlsplit(public_detail).query)["lang"], ["en"])
def test_parser_id_is_deterministic_and_matches_project_format(self) -> None:
origin_id = "mobile.de:123"
@@ -69,9 +73,11 @@ class TestMobileDeRequirements(unittest.TestCase):
self.assertEqual(parser_id, MobileDeMapper._parser_id(origin_id))
self.assertNotEqual(parser_id, origin_id)
def test_mapper_contains_no_cyrillic_literals(self) -> None:
def test_mapper_translates_russian_source_values_to_english_enums(self) -> None:
mapper_path = Path(__file__).parents[1] / "mobilede_scraper" / "mobile_de" / "mapper.py"
self.assertIsNone(re.search(r"[А-Яа-яЁё]", mapper_path.read_text(encoding="utf-8")))
mapper_text = mapper_path.read_text(encoding="utf-8")
self.assertIn('"автоматическая": "AT"', mapper_text)
self.assertIn('"черный": "black"', mapper_text)
def test_upsert_uses_origin_id_and_migrates_legacy_parser_id(self) -> None:
with tempfile.TemporaryDirectory() as directory: