# Парсинг японских цен: иены, полноширинные цифры и налоговые метки

Source: https://ipvolt.com/ru/blog/japanese-price-parsing
Markdown: https://ipvolt.com/ru/blog/japanese-price-parsing.md
Language: ru

[ipvolt — главная](https://ipvolt.com/ru.md) / [Блог](https://ipvolt.com/ru/blog.md) / Парсинг японских цен: иены, полноширинные цифры и налоговые метки

Анализ
Опубликовано: 2026-10-06
Обновлено: 2026-10-06
Автор: ipvolt team
6 мин чтения

Разбирайте японские цены, не теряя валюту и признак налога. Запустите проверенную Python-фикстуру: полноширинная иена, смешанные цены и намеренные случаи «на проверку».

Парсер японских цен должен возвращать сумму вместе с доказательствами валюты, исходным текстом и признаком включения налога. Сначала выберите одно поле предложения, контролируйте нормализацию Unicode и удерживайте неоднозначные входные данные. Полю со статусом `parsed` всё ещё нужны проверки, прежде чем оно станет принятой записью мониторинга.

Загружаемый пример на Python делает эту границу явной. Его **36 синтетических офлайн-случаев дали 36 ожидаемых классификаций: 11 разобранных полей, 25 исходов «на проверку» и ноль сбоев фикстуры**. Ни одна японская витрина и ни один прокси не тестировались. Полезный результат — воспроизводимый набор решений, включая случаи, когда парсер отказывается выбирать цену.

## В отображении цены могут быть две законные суммы

Национальное налоговое агентство Японии (NTA) приводит такой пример в разъяснениях об отображении полной цены:

```text
10,000円（税込価格11,000円）
```

Сумма, явно включающая налог, — 11 000 иен, хотя первым стоит 10 000. Примеры NTA допускают отображение, в котором есть и суммы с налогом, и суммы без налога. Если взять первое число, это различие потеряется. [NTA № 6902, примеры отображения](https://www.nta.go.jp/taxes/shiraberu/taxanswer/shohi/6902.htm).

Удалять все нецифровые символы ещё хуже: применённый к этой строке, `re.sub(r"\D", "", text)` из Python даёт `1000011000`. Прилагаемый парсер возвращает `review` с причиной `unsupported_or_multiple_price_text`. Из контейнера с несколькими ценами он сумму не выбирает.

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

## Требуйте контекст валюты до разбора

Символ `¥` не доказывает, что речь о японской иене. Unicode определяет U+00A5 и для японской иены, и для китайского юаня, независимо от начертания глифа. Прежде чем передавать `JPY`, получите явный контекст валюты для того же предложения. [Unicode 17, «Yen and Yuan»](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/).

Функция принимает только три ключа, причём `text` — строка длиной 1–200 символов. Вот **синтетические входные данные из фикстуры**; ссылка на доказательство в них намеренно является меткой фикстуры:

```json
{
  "text": "￥１，２９８（税込）",
  "currency": "JPY",
  "currency_evidence": "fixture.selected_offer.priceCurrency"
}
```

Для этих входных данных записан такой результат:

```json
{
  "original": "￥１，２９８（税込）",
  "status": "parsed",
  "normalized": "¥1,298(税込)",
  "amount_yen": 1298,
  "currency": "JPY",
  "currency_evidence": "fixture.selected_offer.priceCurrency",
  "tax_basis": "included",
  "tax_label": "税込"
}
```

В адаптере вызывайте `parse_price(record)` из загруженного модуля с этими тремя ключами. Идентификацию товара, URL, отметку времени и прочий контекст мониторинга держите во внешней записи; лишние ключи во входных данных этой функции дают `invalid_record`.

**Ссылка на доказательство — это утверждение вызывающей стороны.** Функция требует непустую строку, но ничего по ней не запрашивает и не проверяет её подлинность. Авторская проба с намеренно сфабрикованной ссылкой всё равно вернула `parsed`. Поэтому передавать `JPY` только потому, что на странице есть глиф в форме знака иены, значит нарушить задуманный контракт, даже если парсер такую запись пропустит. Проверяйте исходные доказательства валюты отдельно и сохраняйте конфликты.

## Контролируйте нормализацию, прежде чем она изменит поле

Полноширинные цифры могут представлять обычные десятичные цифры, но нормализация совместимости меняет и другие символы. Форма NFKC в Unicode может стирать не только различия в ширине; в Python она доступна через `unicodedata.normalize`. [Цифры совместимости в Unicode](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/), [рекомендации по нормализации](https://unicode.org/faq/normalization.html), [Python unicodedata](https://docs.python.org/3/library/unicodedata.html).

Этот парсер проверяет каждый символ, прежде чем нормализовать всё поле. Он допускает изменения для полноширинного ASCII U+FF01–U+FF5E, идеографического пробела U+3000 и полноширинного знака иены U+FFE5. Остальные символы, которые меняются при NFKC, отправляются на проверку. Грамматика проверяется после нормализации; разрешённое преобразование ширины само по себе не делает входные данные ценой.

Этот порядок важен для `¥①２９８（税込）` и `¥¹298（税込）`. Слепое приведение по совместимости может превратить обведённый или надстрочный символ в обычную цифру. Фикстура удерживает оба случая как `unsupported_compatibility_character`. Она также удерживает обратные косые черты — и ASCII, и полноширинные: то, как символ выглядит в шрифте, не делает его знаком иены.

Сохраняйте `original` рядом с `normalized`, как это делает успешная запись выше. Эта политика с предварительной проверкой относится только к загружаемому парсеру. Это не рекомендация огульно применять NFKC к названиям товаров, идентификаторам или произвольному тексту страницы.

## Сохраняйте признак налога, не вычисляя налог

Парсер принимает одно выражение в целых иенах: `¥1298`, `1298円` или `JPY 1298`, с необязательными правильно сгруппированными запятыми. Поддерживаемая налоговая метка в конце может стоять в скобках или после пробела. Метки `税込` и `税込価格` он сопоставляет с `included`; `税抜`, `税抜き` и `税別` — с `excluded`. Без метки получается `unspecified`.

Ниже — избранные результаты выполненной фикстуры. Если не указано иное, во входных данных `currency: "JPY"` и синтетическая ссылка на доказательство, показанная выше.

| Входное поле | Результат | Последствие для последующего сравнения |
| --- | --- | --- |
| `￥１，２９８（税込）` | `parsed`: 1298, `included` | Храните признак «с налогом» вместе с суммой. |
| `1,180円（税抜）` | `parsed`: 1180, `excluded` | Не сравнивайте эту сумму молча с суммой, включающей налог, так, будто основа у них одинаковая. |
| `1,298円` | `parsed`: 1298, `unspecified` | Если задаче нужен известный признак налога, это требование остаётся нерешённым. |
| `10,000円（税込価格11,000円）` | `review` | Перед разбором выберите нужное поле и подкрепите его доказательствами. |
| `12,98円（税込）` | `review` | Группировка не соответствует этой грамматике. |
| `¥①２９８（税込）` | `review` | Неподдерживаемое изменение по совместимости удерживается до нормализации. |
| `¥1298（税込）`, валюта отсутствует или `CNY` | `review` | Знакомый глиф не может заменить требуемый контекст JPY. |

Здесь **нет ни расчёта по налоговой ставке, ни конвертации валют, ни множителя для центов**. `amount_yen` — целое число в рамках входного контракта этого парсера на целые иены; это не определение единиц, принятых в каждом API. Не выводите недостающую сумму брутто или нетто из соседнего числа.

Грамматика также удерживает диапазоны, рассрочки, баллы, несколько цен, отрицательные числа, десятичные дроби, числовые единицы, записанные кандзи, налоговые метки перед суммой и ведущие нули. Некоторые из них могут быть допустимыми способами отображения цены в магазине, просто выходящими за рамки этой грамматики. Исход `review` означает, что входные данные остаются нерешёнными в рамках этой грамматики, а не что отображение у продавца некорректно.

## Запустите ту же офлайн-фикстуру

Скачайте [parse_price.py](https://ipvolt.com/downloads/japanese-price-parsing/parse_price.py) и [fixtures.json](https://ipvolt.com/downloads/japanese-price-parsing/fixtures.json) в один каталог. Скрипт использует стандартную библиотеку Python; в [README](https://ipvolt.com/downloads/japanese-price-parsing/README.md) описаны входной контракт для Python 3.10 или новее и ограничения. Выполните:

```sh
python3 parse_price.py fixtures.json > replay.json
```

Команда не делает сетевых запросов. Сравните `replay.json` с опубликованным [results.json](https://ipvolt.com/downloads/japanese-price-parsing/results.json). Совпадающий прогон сообщает `cases: 36`, `passed: 36` и `failed: 0`. Эти 25 исходов «на проверку» — ожидаемые решения, поэтому они не считаются сбоями фикстуры.

Фикстура проверяет каждое объявленное ожидаемое поле и сохраняет полные фактические выходные данные. Код выхода 0 означает, что ожидания фикстуры совпали; код 1 — что хотя бы одно не совпало; код 2 сообщает о некорректной или нечитаемой фикстуре. Ни один из этих кодов не является сигналом приёмки данных витрины.

Исходная [запись об окружении](https://ipvolt.com/downloads/japanese-price-parsing/environment.json) фиксирует Python 3.14.7 с базой данных Unicode 16.0.0. Авторский повторный прогон на Python 3.14.8, тоже с базой данных Unicode 16.0.0, дал тот же полный JSON с результатами. Ссылки на документацию Unicode 17 не означают, что исполняемый код использовал базу данных Unicode 17.

## Решите, пригодно ли разобранное поле

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

Например, в фикстуре разбираются оба поля: 1298 иен с налогом и 1180 иен без налога. Это не делает разницу между их числами измеренным изменением цены. Поле без метки тоже может пройти разбор и при этом остаться непригодным для сравнения, которому нужны цены с налогом.

Отдельный [кейс о проверке цены и валюты](/ru/blog/product-price-currency-validation) разбирает противоречивые сигналы предложения и витрины. Если для сбора данных нужен ещё и японский выход или мобильный доступ через определённого оператора, используйте для этих доказательств [руководство по оценке прокси Японии](/ru/guides/japan-proxies). Локальный результат разбора не даёт никаких доказательств о стране, сети или доступности выхода.

*Метод: исследование источников и синтез при участии агента, с выполненными синтетическими фикстурами и отдельно описанной пробой ограничений 6 октября 2026 года. Эти случаи демонстрируют заявленное поведение парсера; они не являются ни выборкой японских ритейлеров, ни бенчмарком точности. Ни витрины, ни прокси, ни расчёт налога не тестировались.*

[Сообщите мне, когда откроется доступ](/ru/blog/japanese-price-parsing#waitlist-blog-end). Одно письмо, когда откроется доступ. Больше ничего.

## Источники

- [No.6902 「総額表示」の義務付け](https://www.nta.go.jp/taxes/shiraberu/taxanswer/shohi/6902.htm)
- [Unicode 17.0.0, Chapter 22: Symbols](https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-22/)
- [FAQ: Normalization](https://unicode.org/faq/normalization.html)
- [Python unicodedata](https://docs.python.org/3/library/unicodedata.html)

## Узнайте, когда откроется доступ к ipvolt.

Пока вы здесь

ipvolt в разработке. Оставьте email, и мы один раз напишем, когда откроется доступ.

Одно письмо, когда откроется доступ. Больше ничего.

[Получить ранний доступ](https://ipvolt.com/ru/blog/japanese-price-parsing#waitlist-blog-end)

[Конфиденциальность](https://ipvolt.com/privacy)


## Похожие статьи

- [SOCKS5 и SOCKS5h: в чём разница и что отправляют 6 клиентов](https://ipvolt.com/ru/blog/socks5-vs-socks5h.md) (Сравнение, 4 окт. 2026 г., 7 мин чтения): socks5:// не везде означает локальный DNS. Мы записали, что curl, Requests, HTTPX, aiohttp, Playwright и Node отправляют SOCKS5-прокси для каждой схемы URL.
- [CONNECT tunnel failed, response 403: почему это ловят ИИ-агенты](https://ipvolt.com/ru/blog/connect-tunnel-failed-403.md) (Анализ, 2 окт. 2026 г., 7 мин чтения): curl вашего агента падает с CONNECT tunnel failed, response 403, хотя другие хосты работают. Прокси отказал в туннеле. Как понять, кто его заблокировал, и что исправить.
- [API коэффициентов или скрапинг: таблица расчёта затрат](https://ipvolt.com/ru/blog/betting-odds-api-vs-scraping.md) (Сравнение, 28 сент. 2026 г., 7 мин чтения): Сравните API коэффициентов и разрешённый скрапинг по охвату, свежести данных и смоделированной стоимости сбора с помощью редактируемой таблицы с явными допущениями.

## Связанные руководства

- [Прокси Японии: проверка геолокации IP и сетей au/UQ и Rakuten](https://ipvolt.com/ru/guides/japan-proxies.md): Оценивайте прокси Японии по отдельным доказательствам геолокации IP, выхода и мобильного доступа. Разберитесь с брендами au/UQ и роумингом Rakuten до приёмки образца.
- [Прокси в Python Requests: словарь proxies, аутентификация, SOCKS5](https://ipvolt.com/ru/guides/python-requests-proxy.md): Настройка прокси в Python Requests: словарь proxies, значения по умолчанию в Session, учётные данные, SOCKS5 через requests[socks], переменные окружения и ProxyError.
- [Ротируемые и sticky-прокси: планируйте непрерывность сессии](https://ipvolt.com/ru/guides/rotating-vs-sticky-proxies.md): Выбирайте ротацию под наименьший законченный сценарий, отличайте привязку к выходу от cookie и проверяйте, что происходит, когда sticky-сессия завершается раньше срока.

## О ipvolt

Технический анализ от команды ipvolt.

Доступ к ipvolt пока не открыт.

[Читать оригинал на английском](https://ipvolt.com/blog/japanese-price-parsing.md)
