Блог apiauto.space

Машина 2019 года за $7. Что ломается, когда импортёр подключает Encar к своему сайту

В корейской выдаче мы нашли Kia Carnival с ценой 10 000 вон, примерно $7,47. Полная стоимость автомобиля из этой цифры не следует: карточка относится к аренде. Разобрали 200 первых результатов сортировки по цене, проверили тип сделки и собрали схему каталога, которая не превращает такие объявления в предложение купить машину за несколько долларов.

Автомобиль перед стеной договоров — обложка расследования

Если на сайте импортёра есть кнопка «сначала дешёвые», но тип сделки не учитывается, первые позиции покажут клиенту цены, которые нельзя читать как цену покупки машины. По нашему замеру 6 ноября среди 200 первых объявлений корейского каталога с годом выпуска от 2019-го при сортировке по цене 101 запись была помечена как лизинг, 51 — как аренда, и только 48 — как обычная продажа. То есть 76% первых результатов требовали иного объяснения цены.

Самая дешёвая карточка в этой выдаче — Kia Carnival Hi-Limousine 2025 года. В ответе API её цена составляет 10 000 вон, или $7,47 по указанному в записи курсу, а raw.sell_type равно rental. Это реальная запись каталога, но не доказательство, что автомобиль можно купить за семь долларов. Что входит в эту сумму и какие платежи предусмотрены договором, из данных не видно.

Ниже разбираем, почему порог по цене не чинит выдачу, какой фильтр работает, что ещё нужно каталогу после него и где у такого фильтра границы.

В начале выдачи стоят не те сделки

Тип сделки в ответеОбъявлений из 200Доля
Лизинг, lease10150,5%
Аренда, rental5125,5%
Обычная продажа, normal4824%

Медиана указанной цены среди этих 200 записей — около $676. Это медиана разных видов предложений, поэтому о цене покупки автомобиля она ничего не говорит. В отдельной выборке из 1000 корейских машин 2020 года и новее с фотографиями, взятых из начала обычной выдачи, лизинг и аренда составили 133 записи. Разница между 13,3% и 76% показывает, насколько сортировка по возрастанию цены усиливает проблему.

Сортировка в корейском сегменте идёт по исходной сумме в вонах. Значение в долларах — производное поле с курсом и датой в raw.fx. Оно удобно для сопоставления рынков, но не превращает разные сделки в один товар. Даже без конвертации первые результаты остались бы теми же: проблема в типе предложения, а не в округлении $7,47 до $7 в заголовке.

Автомобили расходятся по трём дорожкам типов сделки
На первом экране «самых дешёвых» обычных продаж меньше четверти. Иллюстрация передаёт идею; точные доли — в таблице выше. Данные: apiauto.space, 6 ноября 2026 года. Изображение создано OpenAI Image Generation.

Вот три карточки из начала выдачи. Значения получены из API в момент замера, страница источника может измениться или исчезнуть.

ОбъявлениеЦена в карточке APIТип сделки
Kia Carnival Hi-Limousine, 202510 000 ₩ / $7,47rental
BMW X5, 2022100 000 ₩ / $74,71lease
Renault Korea Twizy, 2019990 000 ₩ / $739,59normal

У этих трёх записей одинаковое поле price, но разный смысл для каталога импортёра: аренда, лизинг и обычная продажа. Даже у Twizy остаются вопросы состояния, комплектации и итоговой стоимости ввоза. Классификация отделяет виды сделки; она не заменяет проверку условий конкретного объявления.

Проверка по одному полю защищает от конкретной ошибки интерфейса: подписи «купить за» рядом с суммой аренды или лизинга. Называть эти суммы ежемесячным платежом она тоже не позволяет: условий в данных нет. Пока они не прочитаны в первичном объявлении и договоре, честная подпись в своём каталоге — «цена указана в объявлении, тип сделки: аренда» или отказ от показа такой карточки в поиске машин для покупки. Мы выбрали второй путь для демонстрационной выдачи.

Здесь проявляется ошибка модели данных. Поле с числом само по себе не обещает «столько стоит автомобиль». Такое обещание добавляет сайт, когда ставит над числом слово «цена» и кнопку «купить». Если в системе один общий компонент карточки для продажи, аренды и лизинга, без проверки типа сделки он может показать неверный смысл суммы. Лучше сделать вид сделки обязательным условием отображения цены. Для неизвестного вида не подставлять normal по умолчанию: неизвестность должна остаться видимой в данных и не превращаться в предложение.

Это правило стоит применить и к сортировке, и к фильтру «до $20 000», и к подборке, которую менеджер отправляет в мессенджер. Иначе первая страница станет честной, а соседний раздел «похожие машины» снова покажет лизинговый X5 как дешёвую альтернативу. Одно условие ordinary_sale должно выполняться в общем месте подготовки каталога, а не в каждом интерфейсном блоке. Прежде чем включать аренду или лизинг в продукт, для них понадобится свой набор полей и понятные подписи платежей.

{
  "id": "encar:42389850",
  "year": 2025,
  "price": {"amount": "10000.00", "currency": "KRW"},
  "price_usd": "7.47",
  "raw": {"sell_type": "rental"},
  "is_active": true
}

Сокращённый фрагмент ответа /v1/cars/encar:42389850: оставлены только поля, о которых идёт речь. Значение price_usd пересчитано по курсу ECB, дата курса указана в raw.fx записи.

Почему порог «от $3000» не чинит выдачу

Первое желание — убрать всё, что дешевле условных $3000. Так карточка за $7 исчезнет. Вместе с ней исчезнут дешёвые обычные продажи: в нашем срезе Twizy с sell_type=normal стоила $739,59. А лизинговое объявление с указанной ценой выше порога останется. Порог отвечает на вопрос «какое число записано», но не на вопрос «какую сделку предлагают».

Рабочее правило для витрины покупки проще: показывать в ней только записи с raw.sell_type == "normal". Неизвестное значение лучше отложить на проверку, а лизинг и аренду вывести в отдельные сценарии, если сайт вообще ими занимается. Сейчас наш API не поддерживает серверный параметр sell_type; фильтр выполняется после получения страниц. Это влияет на пагинацию: если запросить 20 записей и отбросить неподходящие, на экране может остаться три, хотя в каталоге дальше есть нормальные продажи.

Ценовой фильтр пропускает документы вместе с машинами
Цена помогает сортировать сравнимые предложения. До сортировки придётся отделить продажи от лизинга и аренды. Изображение создано OpenAI Image Generation.

Поэтому сначала дочитываем страницы по next_cursor, затем набираем нужное число подходящих автомобилей. Для большого каталога можно сохранять уже отфильтрованный сегмент в своей базе и сортировать его там. В демонстрационном коде рядом со статьёй показаны запрос страниц и отбор normal; он не сохраняет данные и не создаёт заявку.

def ordinary_sale(car):
    return (
        car.get("is_active") is True
        and (car.get("raw") or {}).get("sell_type") == "normal"
        and car.get("price_usd") is not None
        and float(car["price_usd"]) > 0
    )

cursor = None
sales = []
while len(sales) < 20:
    page = get("/v1/cars", market="kr", sort="price",
               year_min=2019, limit=100, cursor=cursor)
    sales.extend(car for car in page["items"] if ordinary_sale(car))
    cursor = page["next_cursor"]
    if cursor is None:
        break
sales = sales[:20]

Здесь важна последовательность. Сервер сортирует все объявления по цене и возвращает страницу, клиент отбирает обычные продажи и только после этого проверяет, набралось ли 20 машин. Если сделать срез page["items"][:20] до фильтра, первый экран снова окажется неполным. Если отсортировать только одну страницу и забыть next_cursor, появятся пропуски. Скрипт не обещает, что все 20 машин доступны прямо сейчас; он формирует кандидатов для актуальной проверки.

Каталог нужен не ради красивого списка

Исправление первой страницы кажется мелочью, пока каталог считают оформлением сайта. Но это путь от поиска машины до заявки. Для масштаба: в опубликованном кейсе агентства Darvin исполнитель сообщает о 175 тысячах уникальных посетителей сайта импортёра из Южной Кореи за год, 65 тысячах из органического поиска, 18 тысячах заявок, из которых 16 тысяч квалифицированные, и 500 проданных автомобилях. Это результаты чужого проекта по словам его исполнителя, а не показатели нашего каталога. Там же упомянуты машины без полной информации и обновление базы трижды в неделю.

Каталог ведёт автомобиль и заявку к салону
За цифрами кейса стоит сайт другой команды. Здесь картинка только показывает путь от каталога к обращению. Изображение создано OpenAI Image Generation.

Покупатель не должен выяснять после отправки заявки, что «цена» относилась к аренде или машина исчезла из исходной выдачи. Поэтому после фильтра по типу сделки каталогу нужны ещё три вещи: синхронизация, честная страница снятой машины и обновляемые фото.

Три слоя вместо одного ночного импорта

Для собственного каталога мы разделяем три операции: загрузить выбранный сегмент, например Kia с 2019 года; обновлять его и отслеживать снятые объявления; перепроверять конкретную карточку, когда посетитель её открывает, и особенно перед отправкой подборки клиенту. Это разные проверки с разной ценой и частотой.

Первичная загрузка. Страницы /v1/cars читают по next_cursor, пока он не станет null. offset здесь не нужен: в движущемся каталоге он может пропустить записи или вернуть повтор. Ключом в базе служит стабильный id, рядом хранятся тип сделки, цена, last_seen_at, is_active, ссылка на оригинал и время собственного обновления.

Обновления. Лента /v1/changes даёт car_id, тип события и время. Она не фильтруется по марке или модели и не несёт полной карточки, поэтому для маленького сегмента бывает дешевле опрашивать новые объявления с sort=-first_seen. Для цен сохранённых машин подходят price_drop и price_up, но машина, отсечённая по цене при загрузке, после снижения сама в сегмент не попадёт.

Открытие карточки. Перед показом деталей проверяем /v1/cars/{id}. Если is_active=false, убираем кнопку заявки на эту машину. Проверка через API даёт состояние копии каталога, а не мгновенное подтверждение продавца; для дорогой сделки наличие и условия подтверждаются у источника.

Три операции синхронизации каталога
Слева сегмент попадает в локальную базу, затем приходят изменения, а при открытии карточки происходит отдельная проверка. Иллюстрация создана OpenAI Image Generation.
GET /v1/cars?market=kr&brand=Kia&year_min=2019&limit=100
GET /v1/cars?market=kr&brand=Kia&year_min=2019&limit=100&cursor=<next_cursor>
GET /v1/changes?market=kr&since=<ISO-8601>&type=disappeared&limit=100
GET /v1/cars/encar:42389850

Демонстрационный скрипт показывает только отбор продаж. Для полноценного сервиса к нему нужны база данных, расписание, повтор запросов с контролем ошибок, мониторинг возраста данных и проверка условий сделки.

Машина исчезла, а URL остался

В предыдущем суточном замере по Корее мы насчитали 4657 событий disappeared при 142 тысячах активных машин. Это данные одного дня, а не средняя скорость исчезновения; «снята» не означает «продана». В новом срезе число активных корейских объявлений было 142 912. Если сайт обновляет каталог раз в несколько дней, шанс открыть устаревшую карточку растёт, но долю таких ошибок на своём сайте надо измерять отдельно.

Для снятой машины есть два разумных ответа. Если карточка почти не несёт самостоятельной пользы, страницу закрывают корректным HTTP-ответом и предлагают поиск похожих машин. Если на URL есть полезная информация о модели, страницу можно оставить, пометив экземпляр снятым и убрав заявку на него. Нельзя подменять снятую машину другой под прежним id: покупатель и менеджер начнут обсуждать разные предметы. А «похожие» должны сохранить смысл запроса, например число мест, модельный год и бюджет.

Пустое парковочное место и уходящая карточка объявления
Страница может пережить автомобиль. Важнее всего честно убрать действие «оставить заявку на этот экземпляр». Изображение создано OpenAI Image Generation.

Различайте три времени: когда продавец изменил объявление, когда изменение увидел источник данных и когда его прочитал ваш сайт. Даже ежечасный запрос не превращает базу в «наличие в реальном времени». На карточке полезно показывать время последней проверки.

Фотографии тоже не вечные

В API фото приходят как подписанные ссылки со сроком действия около суток. URL, сохранённый в базе месяц назад, может уже не открыться, хотя машина активна. Ссылки обновляют вместе с данными и держат запасную карточку без фото. photo_count говорит лишь, сколько ссылок было в ответе. Право на повторное размещение чужих изображений из доступности URL не следует: его проверяют по условиям источника.

Фотографии машины постепенно выцветают
Постоянный идентификатор машины и временный адрес фотографии требуют разного срока жизни в базе. Изображение создано OpenAI Image Generation.

Полный рынок быстро превращается в счётчик записей

На момент проверки справочник API показывал 142 912 активных записей по Корее и 237 701 по Китаю, вместе 380 613. Это объём начальной загрузки, если копировать оба рынка целиком, ещё до обновлений. Месячный объём одним умножением не получить: он зависит от того, какие события читать, сколько карточек после них запрашивать, какие сегменты хранить и как часто перепроверять открытые страницы.

СценарийЧто считываетсяКак считать расход записей
Одна марка и нужные годыСтраницы /v1/cars выбранного сегментаЧисло реально возвращённых машин, включая лизинг и аренду до локального фильтра
Полная начальная копия KR + CNОба активных рынка380 613 записей на момент замера
Лента измененийСобытия двух рынковКаждое полученное событие плюс отдельные запросы карточек, если они нужны
Проверка карточки перед заявкойОдин /v1/cars/{id}Одна возвращённая карточка на проверку

Полная копия даёт максимум свободы для фильтров, но съедает объём ещё до первой заявки. Узкий сегмент дешевле и проще поддерживать. До разработки достаточно записать четыре числа: сколько машин вернёт первичный фильтр, сколько новых появляется в сегменте за день, сколько событий по сохранённым id вы обрабатываете и сколько карточек открывают посетители. Последнее легко забыть: проверка при каждом открытии создаёт нагрузку даже при неизменном каталоге, поэтому ответ стоит кэшировать на короткий срок.

Множество машин рядом с небольшим выбранным сегментом у сервера
«Загрузить всё» — вполне конкретное решение о 380 613 записях в начальном снимке. Число относится к 6 ноября 2026 года; изображение создано OpenAI Image Generation.

У фильтра есть границы, о которых надо сказать покупателю

raw.sell_type решает одну задачу: не смешивать виды сделки. Он не делает все поля корейской карточки полными и достоверными. В нашей выборке из 1000 объявлений с фотографиями медиана числа фото была четыре. По API нельзя считать raw.has_accident=false доказательством отсутствия аварий: в этом срезе поле было false у всех 1000. То же относится к raw.has_inspection; оно также было false у всех. Отсутствие положительного флага — не заключение эксперта.

Для Кореи в нормализованной карточке отсутствуют коробка передач и мощность двигателя. Объём двигателя заполнен лишь у небольшого числа записей. Поэтому фильтр по мощности, расчёт ввозных платежей или обещание «без ДТП» нельзя достраивать из этих полей. Нужны документы и отдельная проверка конкретной машины. Даже normal говорит только о типе объявления, а не о состоянии автомобиля или цене «под ключ».

Это разница между «мы можем вывести карточку» и «мы можем ответить на вопрос покупателя». Если для юридически или финансово значимого расчёта не хватает поля, сайт должен передать вопрос человеку и документам, а не заполнять пробел типовым значением. Для разработчика это отказ от идеальной схемы данных; для покупателя — разница между честной неопределённостью и ложной уверенностью.

Незаполненные поля на чертеже автомобиля
Пустое поле лучше показать пустым, чем превратить его в уверенное «нет аварий». Изображение создано OpenAI Image Generation.

Как мы считали

Замер сделан 6 ноября 2026 года в 01:07 мск через каталог apiauto.space. Запрос: рынок kr, год от 2019-го, sort=price, две страницы по 100 записей. Мы считали значения raw.sell_type в полученных карточках. Это первые 200 результатов сортировки, а не случайная выборка всего Encar и не доля лизинга на рынке. Сравнительная выборка из 1000 машин тоже взята из начала выдачи; обе зависят от момента запроса и порядка выдачи.

Страницу Carnival на Encar мы открыли отдельно. Номер объявления и модель совпадают с API; в описании продавца есть корейская фраза 최고의렌트조건 — «лучшие условия аренды». Точную сумму на странице в момент проверки прочитать не удалось, поэтому 10 000 вон и пересчёт в доллары относятся к ответу API. Фраза продавца подтверждает контекст аренды, но не раскрывает условия договора.

Вывод

Семь долларов оказались числом в карточке аренды, а 76% начала ценовой сортировки — лизингом и арендой. Для сайта импортёра порядок действий получается обратным привычному: сначала определить тип сделки и актуальность карточки, затем сравнивать цены. Как у вас устроена страница автомобиля после того, как исходное объявление исчезло?

Данные: apiauto.space, замер 6 ноября 2026 года, 01:07 мск. Мы сводим открытые объявления разных площадок в единый формат и не аффилированы с Encar. Методика и сокращённые обезличенные примеры сохранены в файле замера; демонстрационный код — в приложении.