Парсер рекламных поверхностей с boards.by с экспортом в JSON и XLSX.
- Забирает полный каталог конструкций через
POST https://boards.by/local/ajax/map.php. - Разбивает
PROPERTY_SIDE_VALUEна отдельные стороны. - Для выбранных конструкций догружает карточки вида
https://boards.by/banner/{code}/?side={side}. - Нормализует поля под тестовый формат.
- Выгружает результат в
result.jsonиresult.xlsx.
python -m pip install -r requirements.txt
python main.pyПо умолчанию парсер собирает:
- минимум
100уникальных конструкций (gid) - минимум
150side-записей
и сохраняет результат в:
result.jsonresult.xlsx
Можно изменить лимит и пути:
python main.py --limit-gids 120 --limit-sides 220 --json-out custom.json --xlsx-out custom.xlsx --verbosemain.py- CLI entrypoint.boards_parser/client.py- HTTP-клиент и запросы кboards.by.boards_parser/parser.py- отбор конструкций, парсинг карточек, сбор целевых записей.boards_parser/normalize.py- нормализация сторон, размеров, типов и форматов.boards_parser/exporters.py- экспорт в JSON и Excel.
Основной источник списка конструкций - JSON из POST /local/ajax/map.php.
Из него берутся:
IDкак реальныйgid.NAMEкак fallback для адреса.CODEдля перехода в карточку.PROPERTY_SIDE_VALUEдля разбиения на стороны.PROPERTY_TYPE_VALUEкак исходный тип конструкции.PROPERTY_LONGITUDE_VALUEиPROPERTY_LATITUDE_VALUEдля координат.
Одна конструкция на сайте может содержать несколько сторон в одном поле, например:
А,ВА1,А2,А3A,B,C,D
Парсер делит такое значение на отдельные записи. Новые gid не генерируются: если сайт показывает один ID на конструкцию, этот ID повторяется у всех ее сторон. Это сознательно сделано, потому что отдельные side-id источник не публикует.
Из карточки добираются:
- заголовок страницы для
address; - блок
dl_elementдляФормат,Тип,Сторонаи других свойств; - описание конструкции для fallback-парсинга
display_typeиsize.
У источника поля координат названы наоборот:
PROPERTY_LONGITUDE_VALUEфактически содержитlatPROPERTY_LATITUDE_VALUEфактически содержитlon
Парсер это явно исправляет в итоговой выгрузке.
Используется комбинация поля Тип и текста описания.
Призматрон,Призмавижн->ПризматронСкроллили явное упоминаниескроллв описании ->СкроллерLED - экран,Светодиодный экран,Экран->Видеоэкран- если источник явно указывает на динамическую конструкцию, но не позволяет надежно отнести ее к одному из допустимых классов ->
null - во всех остальных случаях ->
Статика
Используется поле Тип.
Билборд->БилбордыАрка->АркиПутепровод->МостыБрандмауэр->БрандмауэрыСитиборд->СитибордыСветовой короб,Юнипол,Мегаборд, а также типы, которые описывают только механику показа (Призматрон,Скролл,Экран) ->Нетиповые форматы
Почему Нетиповые форматы: сайт в поле Тип смешивает физический формат конструкции и технологию показа. Для части объектов надежно восстановить формат из справочника нельзя.
Нормализация размеров:
- разделители
х,×,*приводятся кx - убираются пробелы и единицы измерения
- запятая приводится к точке
- если размер указан в миллиметрах или сантиметрах, он конвертируется в метры
Примеры:
6*3м->6x38 х 4 м.->8x43,72х2,74 м->3.72x2.746020*3080мм->6.02x3.08
Если в источнике нет пары размеров, поле остается null.
Заполняется только когда признак можно определить надежно:
trueдля явно светящихся носителей вродеLED - экран,Светодиодный экран,Экран,Световой коробtrueилиfalse, если в карточке когда-либо появится явное полеПодсветка/Освещение- иначе
null
Заполняется только из явного поля карточки. Если сайт не отдает материал, в выгрузку идет null.
Чтобы в тестовой выгрузке были представлены разные типы конструкций, конструкции отбираются не просто по первым ID, а раундами по Типу. Это дает более показательный набор объектов для проверки маппинга.
--limit-gids задает минимальное число уникальных конструкций.
--limit-sides задает минимальное число side-записей.
Обе границы применяются одновременно: парсер останавливается только когда выполнены оба условия. Последняя конструкция не режется по сторонам, поэтому итоговое количество строк может быть чуть больше запрошенного.
- Сайт не публикует отдельные идентификаторы сторон, только идентификатор конструкции.
- Поле
Типнеоднородное: часть значений описывает формат носителя, часть - способ смены изображения. materialпочти нигде не указан явно.lightingдля статических конструкций чаще всего не указан явно, поэтому массово выставляетсяnull, а не предположение.- В постановке есть расхождение: в примере JSON поле называется
Material, а в таблице правил -material. В реализации используетсяmaterial, потому что это соответствует общему стилю остальных ключей и разделу с правилами заполнения полей.
JSON:
{
"construction_sides": [
{
"gid": "10118",
"address": "№ 1 г.Молодечно, угол ул.Виленская - ул.Толстого (Центральная площадь)",
"name": "В",
"lon": 26.839621,
"lat": 54.307023,
"construction_format": "Билборды",
"display_type": "Статика",
"lighting": null,
"size": "6x3",
"material": null
}
]
}