Загрузка данных
Ты — senior Python developer и специалист по browser automation/scraping.
Нужно разработать полноценное Windows-приложение с графическим интерфейсом и собрать его в ".exe".
1. Референсный репозиторий
В качестве исходной архитектурной идеи внимательно изучи этот репозиторий:
https://github.com/chernyshov-dp/YMapsGrabber
Это старый grabber для Яндекс.Карт. Он получает данные организаций из Яндекс.Карт, включая название, сайт, ссылку на карточку, рейтинг, отзывы и другие поля.
ВАЖНО:
- репозиторий используй как reference implementation;
- не копируй слепо устаревший Selenium/Safari-код;
- проект должен работать на Windows;
- современный браузерный automation предпочтительно реализовать через Playwright + Chromium;
- приложение должно собираться в standalone ".exe";
- не требовать от конечного пользователя установленного Python;
- не требовать ручной установки браузера, если это можно решить при сборке/первом запуске;
- учитывать актуальную структуру и поведение Яндекс.Карт на момент разработки.
Исходный репозиторий архивирован, поэтому его код необходимо адаптировать к современному состоянию Яндекс.Карт, а не считать его DOM-селекторы вечными.
2. Главная задача приложения
Мне нужен парсер Яндекс.Карт для поиска потенциальных клиентов.
Логика:
Пользователь вводит произвольный поисковый запрос.
Например:
"септики"
После этого приложение должно открыть/использовать Яндекс.Карты и выполнить поиск:
"септики"
с выбранным пользователем городом/регионом.
НЕ ДЕЛАТЬ систему поиска по заранее заданным категориям.
Это принципиально важно.
Не должно быть меню:
- рестораны
- салоны красоты
- стоматологии
- магазины
- автосервисы
и т. п.
Вместо этого должен быть ОДНО поле:
"Поисковый запрос"
Пользователь сам вводит любое слово или словосочетание.
Примеры:
- септики
- монтаж септиков
- натяжные потолки
- окна
- пластиковые окна
- строительство домов
- бухгалтерские услуги
- ремонт квартир
Приложение передаёт этот запрос непосредственно в поиск Яндекс.Карт.
3. Основной фильтр — только организации БЕЗ САЙТА
Это ключевая функция приложения.
Нужно находить организации, у которых в карточке Яндекс.Карт отсутствует сайт.
Алгоритм:
1. Получить результаты поиска Яндекс.Карт.
2. Открывать/анализировать карточки организаций.
3. Определять наличие сайта.
4. Если у организации есть сайт — НЕ показывать её в итоговом списке.
5. Если сайта нет — добавить организацию в результаты.
Важно корректно различать:
- настоящий внешний сайт организации;
- социальные сети;
- агрегаторы;
- ссылки Яндекс;
- ссылки на карты;
- рекламные/служебные ссылки.
Основной критерий текущей версии приложения:
"website отсутствует"
То есть нам нужны организации, у которых Яндекс.Карты не показывает официальный сайт.
Если структура страницы позволяет определить именно наличие поля "Сайт", использовать это как основной критерий.
Не пытаться делать дополнительный внешний поиск сайта через Google/Bing/поисковики на первом этапе.
4. Данные, которые нужно выводить
В таблице результатов нужны только:
1. Название
Название организации.
Название должно быть КЛИКАБЕЛЬНЫМ.
При клике открывается URL карточки этой организации на Яндекс.Картах в браузере по умолчанию.
2. Рейтинг
Например:
5.0
4.9
4.8
4.5
и т. д.
3. Телефон
Основной телефон организации.
Например:
+7 (999) 123-45-67
Если у организации несколько телефонов, в первой версии можно выводить основной телефон.
Если телефона нет — выводить:
"Нет телефона"
или "—".
Больше в основной таблице ничего не нужно.
Не выводить сейчас:
- адрес;
- часы работы;
- описание;
- категории;
- меню;
- услуги;
- количество отзывов;
- фотографии.
Архитектуру при этом сделать расширяемой, чтобы эти поля можно было добавить позже.
5. Фильтр рейтинга
В интерфейсе должен быть фильтр:
"Рейтинг от"
и
"Рейтинг до"
Например пользователь может поставить:
от 4.0
до 5.0
Тогда приложение показывает только организации:
4.0 <= rating <= 5.0
Другие примеры:
3.0 — 5.0
4.5 — 5.0
4.8 — 5.0
5.0 — 5.0
Если пользователь не хочет ограничивать рейтинг, должна быть возможность выбрать:
"Любой рейтинг"
По умолчанию поставить:
от 0
до 5
6. Фильтр города / региона
Нужен отдельный выбор территории поиска.
Минимум:
- Россия
- конкретный город
Например:
Москва
Санкт-Петербург
Казань
Екатеринбург
Новосибирск
Краснодар
Ростов-на-Дону
и т. д.
Но не ограничиваться несколькими городами, если технически можно сделать нормальный выбор.
Лучший вариант интерфейса:
поле/combobox:
"Город или регион"
с возможностью ввести произвольный город.
Например:
"Москва"
При этом поисковый запрос остаётся отдельным:
Поисковый запрос: "септики"
Город: "Москва"
И приложение выполняет поиск:
"септики Москва"
через интерфейс/URL поиска Яндекс.Карт.
7. Вариант "Вся Россия"
Нужен режим:
"Вся Россия"
При выборе этого режима приложение должно искать по России максимально широко, насколько это реально возможно средствами Яндекс.Карт.
Но НЕ притворяться, что один запрос гарантированно возвращает абсолютно все организации России.
Нужно учитывать ограничения выдачи Яндекс.Карт, пагинацию/ленивую загрузку, ограничение количества результатов и возможные ограничения самого сервиса.
Если для полноценного поиска по России необходимо разбивать задачу на города/регионы, архитектура должна позволять сделать это позже.
Для первой версии:
- реализовать город;
- реализовать режим "Вся Россия" как отдельный режим;
- не заявлять пользователю о гарантированном полном покрытии всей базы Яндекс.Карт.
8. Поиск должен идти именно через Яндекс.Карты
Не использовать сторонние базы организаций вместо Яндекс.Карт.
Основной источник данных:
Яндекс.Карты.
Логика:
GUI
↓
поисковый запрос
↓
город/регион
↓
Яндекс.Карты
↓
получение результатов
↓
получение карточек организаций
↓
проверка наличия сайта
↓
проверка рейтинга
↓
извлечение телефона
↓
вывод подходящих организаций.
9. Важный момент с выдачей
Не ограничиваться первыми 10 организациями.
Нужно реализовать максимально корректный сбор результатов из доступной выдачи:
- прокрутка результатов;
- lazy loading;
- переход/открытие карточек;
- сбор новых результатов;
- остановка, когда новых результатов больше нет;
- защита от дублей.
Сделать настройку:
"Максимум результатов"
Например:
100
500
1000
или произвольное число.
По умолчанию, например, 100.
Если Яндекс.Карты физически не отдают больше результатов, приложение должно остановиться корректно и показать фактически найденное количество.
10. Удаление дублей
Одна организация не должна появляться несколько раз.
Использовать для дедупликации наиболее стабильный идентификатор организации:
- ID/URI/oid карточки Яндекс.Карт, если доступен;
- в крайнем случае комбинацию нормализованного названия + телефона.
Приоритет:
1. Yandex organization ID / oid;
2. URL карточки;
3. телефон + название.
11. GUI
Сделать нормальное современное desktop GUI для Windows.
Можно использовать PySide6.
Интерфейс должен быть максимально простым.
Верхняя часть:
Поисковый запрос
[____________________________]
Например:
"септики"
Город / регион
[ Москва ▼ ]
или:
[____________________________]
Рейтинг
От [ 4.0 ] До [ 5.0 ]
Сайт
☑ Только без сайта
Этот checkbox можно оставить включённым по умолчанию.
Максимум результатов
[ 100 ]
Кнопки:
[ НАЧАТЬ ПОИСК ]
[ ОСТАНОВИТЬ ]
12. Статус выполнения
Под фильтрами сделать статус:
"Поиск запущен..."
Показывать прогресс:
Найдено организаций: 127
Проверено: 93
Подходит: 21
Пропущено с сайтом: 72
Например:
Поиск: 43%
Проверено: 150 / 350
Важно не делать фальшивый progress bar, если реальное количество результатов заранее неизвестно.
Можно использовать индикатор активности, если количество неизвестно.
13. Таблица результатов
Основной элемент GUI — таблица.
Колонки:
Организация| Рейтинг| Телефон
Септик-Сервис| 4.9| +7 999 123-45-67
Септики 24| 4.8| +7 999 222-11-33
Название организации должно быть визуально понятно как ссылка.
При клике:
открывать карточку организации в браузере:
URL Яндекс.Карт.
Не открывать сайт организации, потому что мы специально собираем организации БЕЗ сайта.
14. Сортировка
Добавить сортировку таблицы.
Минимум:
- по названию;
- по рейтингу;
- по телефону.
По умолчанию сортировать по рейтингу по убыванию.
То есть:
5.0
5.0
4.9
4.9
4.8
...
15. Экспорт
Даже если пользователь сейчас попросил только три поля, обязательно сделать экспорт результатов.
Кнопки:
[ Экспорт CSV ]
[ Экспорт Excel ]
В экспорт включать:
- название;
- рейтинг;
- телефон;
- URL карточки Яндекс.Карт.
URL нужен для удобства, даже если в GUI он скрыт и открывается через клик по названию.
CSV должен корректно работать с кириллицей.
Excel — ".xlsx".
16. Сохранение результатов
Добавить возможность сохранить текущий результат.
Не обязательно делать сложную БД.
На первом этапе достаточно:
- CSV;
- XLSX;
- JSON.
Внутреннюю модель данных сделать примерно такой:
{
"name": "...",
"rating": 4.9,
"phone": "...",
"website": null,
"yandex_url": "...",
"yandex_id": "..."
}
Поле "website" можно не показывать в основной таблице, но хранить внутри.
17. Логирование
Добавить лог приложения.
Пользователь должен видеть:
- начало поиска;
- поисковый запрос;
- город;
- сколько карточек найдено;
- сколько обработано;
- сколько пропущено из-за сайта;
- сколько не прошло рейтинг;
- сколько добавлено;
- ошибки отдельных карточек.
Ошибки одной организации НЕ должны останавливать весь поиск.
Например:
Ошибка обработки организации X → записать в лог → перейти к следующей.
18. Устойчивость парсера
Это очень важно.
Яндекс.Карты — динамический JavaScript-сайт.
Поэтому:
- не полагаться только на CSS-классы с хешированными именами;
- использовать устойчивые селекторы;
- по возможности искать элементы по semantic attributes, aria-label, data-атрибутам и структуре DOM;
- вынести все селекторы в отдельный модуль;
- сделать fallback-селекторы;
- добавить диагностическое логирование;
- не падать при изменении одного элемента карточки.
Создать отдельный слой:
"yandex_maps_parser.py"
и отдельную модель:
"models.py"
GUI не должен содержать scraping-логику.
19. Архитектура проекта
Предпочтительная структура:
project/
│
├── main.py
├── requirements.txt
├── README.md
├── build_exe.bat
│
├── app/
│ ├── init.py
│ ├── gui.py
│ ├── models.py
│ ├── settings.py
│ │
│ ├── parser/
│ │ ├── init.py
│ │ ├── yandex_maps.py
│ │ ├── selectors.py
│ │ └── extractor.py
│ │
│ ├── filters/
│ │ ├── init.py
│ │ └── organization_filter.py
│ │
│ ├── export/
│ │ ├── init.py
│ │ ├── csv_export.py
│ │ ├── xlsx_export.py
│ │ └── json_export.py
│ │
│ └── utils/
│ ├── logger.py
│ └── browser.py
│
└── assets/
Архитектура должна быть модульной.
20. Асинхронность / GUI
Парсер нельзя запускать в GUI-потоке.
Иначе окно Windows будет зависать.
Использовать:
- QThread;
- QRunnable/QThreadPool;
- или другую корректную модель фоновой работы.
GUI должен оставаться отзывчивым во время парсинга.
Кнопка "Остановить" должна действительно останавливать процесс.
21. Браузер
Для Windows использовать Playwright + Chromium.
Предпочтительно:
Python
PySide6
Playwright
pandas/openpyxl для экспорта при необходимости
PyInstaller для ".exe"
Не использовать Safari/Safaridriver из исходного проекта.
Нужно обеспечить максимально простой запуск на чистом Windows-компьютере.
22. Антидубли и кеширование
Если одна и та же организация встретилась несколько раз — не обрабатывать её повторно.
Добавить in-memory cache.
При необходимости можно сделать локальный cache JSON/SQLite.
Но не усложнять проект без необходимости.
23. Работа с ошибками
Предусмотреть:
- timeout;
- отсутствие телефона;
- отсутствие рейтинга;
- отсутствие сайта;
- изменение DOM;
- captcha;
- блокировку;
- сетевые ошибки;
- закрытие браузера;
- ручную остановку.
Если появилась CAPTCHA/проверка пользователя:
не пытаться обходить её автоматически.
Показать понятный статус:
"Яндекс запросил дополнительную проверку. Завершите её в открытом окне браузера."
После ручного прохождения пользователь должен иметь возможность продолжить работу.
24. Ограничение частоты запросов
Не делать агрессивный параллельный scraping.
Не открывать одновременно сотни карточек.
Использовать умеренную скорость:
- небольшие задержки;
- последовательную обработку карточек либо небольшой controlled concurrency;
- повторные попытки только при временных ошибках.
Цель — стабильность, а не максимальное количество запросов в секунду.
25. Фильтрация должна происходить до отображения
Пример:
Поиск:
"септики"
Город:
"Москва"
Рейтинг:
"4.5 — 5.0"
Только без сайта:
ON
Яндекс.Карты вернули:
1. Компания A — 4.9 — сайт есть
2. Компания B — 4.8 — сайта нет
3. Компания C — 4.2 — сайта нет
4. Компания D — 5.0 — сайт есть
5. Компания E — 4.7 — сайта нет
В таблице должно остаться:
Компания B | 4.8 | телефон
Компания E | 4.7 | телефон
Компания A и D отбрасываются по наличию сайта.
Компания C отбрасывается по рейтингу.
26. Не путать поисковый запрос и категорию
Это отдельное критическое требование.
НЕ делать:
category = "restaurants"
НЕ делать:
category = "beauty"
НЕ делать:
category = "construction"
Всё должно строиться вокруг пользовательского поискового запроса:
"search_query"
Например:
search_query = "септики"
и территории:
location = "Москва"
Далее формируется поиск Яндекс.Карт.
27. URL организации
В модели обязательно хранить:
"yandex_url"
Например URL вида:
https://yandex.ru/maps/...
Конкретный URL получать непосредственно из результата/карточки Яндекс.Карт.
Название в GUI должно открывать именно этот URL.
28. Производительность
Не нужно сразу строить огромную распределённую систему.
Первая версия должна быть:
- стабильной;
- понятной;
- простой;
- Windows-friendly;
- пригодной для сборки в ".exe".
При этом архитектура должна позволять позже добавить:
- прокси;
- многопоточность;
- несколько регионов;
- расширенные фильтры;
- количество отзывов;
- экспорт дополнительных данных;
- базу данных;
- историю поисков.
29. Сборка EXE
Добавить рабочий скрипт:
"build_exe.bat"
который создаёт:
"dist/YandexMapsGrabber.exe"
Использовать PyInstaller.
Продумать включение всех необходимых файлов.
README должен содержать:
1. установку зависимостей для разработки;
2. установку Playwright;
3. запуск в dev-режиме;
4. сборку ".exe";
5. запуск ".exe";
6. описание известных ограничений.
30. Что должно получиться в результате
Я хочу получить не прототип из нескольких файлов, а реально запускаемое Windows-приложение.
После запуска пользователь видит:
---
Yandex Maps Lead Grabber
Поисковый запрос:
[ септики ]
Город / регион:
[ Москва ]
Рейтинг:
от [ 4.0 ] до [ 5.0 ]
☑ Только организации без сайта
Максимум результатов:
[ 100 ]
[ НАЧАТЬ ПОИСК ] [ ОСТАНОВИТЬ ]
---
Статус:
Поиск выполняется...
Найдено: 127
Проверено: 85
Без сайта: 31
Подходит по рейтингу: 24
---
РЕЗУЛЬТАТЫ
Организация Рейтинг Телефон
Септики 24 4.9 +7...
Название кликабельно
Септик-Сервис 4.8 +7...
Название кликабельно
Монтаж Септиков 4.7 +7...
Название кликабельно
---
[ CSV ] [ EXCEL ] [ JSON ]
31. Что сделать первым
Перед написанием большого количества кода:
1. Изучи структуру исходного YMapsGrabber.
2. Определи, какие части его логики можно использовать концептуально.
3. Проверь актуальную структуру Яндекс.Карт.
4. Сделай минимальный рабочий scraper:
- поисковый запрос;
- город;
- получение организаций;
- название;
- рейтинг;
- телефон;
- сайт;
- URL карточки.
5. Реализуй фильтр "без сайта".
6. Реализуй фильтр рейтинга.
7. Затем GUI.
8. Затем экспорт.
9. Затем сборку ".exe".
Не имитируй работу парсера тестовыми данными.
До завершения MVP приложение должно реально получать данные из Яндекс.Карт.
32. Критерии готовности MVP
MVP считается готовым, если:
1. Запускается на Windows.
2. Есть GUI.
3. Можно ввести любой поисковый запрос.
4. Можно указать город.
5. Можно задать диапазон рейтинга.
6. Есть фильтр "только без сайта".
7. Реально выполняется поиск на Яндекс.Картах.
8. Реально собираются организации.
9. Организации с сайтом исключаются.
10. Организации вне диапазона рейтинга исключаются.
11. В таблице показываются:
- название;
- рейтинг;
- телефон.
12. Название кликабельно и открывает карточку Яндекс.Карт.
13. Есть дедупликация.
14. Есть остановка поиска.
15. GUI не зависает.
16. Есть экспорт CSV/XLSX/JSON.
17. Есть логирование.
18. Проект собирается в ".exe".
33. Важное юридическое/техническое требование
Перед использованием кода из исходного YMapsGrabber проверь его лицензию и соблюдай её требования.
Исходный репозиторий распространяется под GPL-3.0, поэтому не надо просто копировать его код в новый проект без учёта условий лицензии.
Также не реализовывай обход CAPTCHA, антибот-защиты или других механизмов безопасности Яндекс.Карт.
Если Яндекс.Карты меняют DOM, архитектура должна позволять быстро обновить селекторы/адаптер без переписывания GUI.
34. Стиль разработки
Пиши production-quality код.
Требования:
- type hints;
- понятные имена;
- docstrings там, где они полезны;
- обработка исключений;
- logging;
- отсутствие огромного "main.py";
- конфигурация отдельно;
- scraping отдельно;
- GUI отдельно;
- экспорт отдельно;
- фильтры отдельно.
Не делай premature optimization.
Сначала добейся корректного рабочего MVP.
После реализации обязательно:
1. запусти приложение;
2. протестируй реальный поиск;
3. исправь ошибки;
4. протестируй фильтр "без сайта";
5. протестируй диапазон рейтинга;
6. протестируй открытие URL организации;
7. протестируй экспорт;
8. проверь сборку ".exe".
В конце предоставь:
- структуру проекта;
- список зависимостей;
- инструкцию запуска;
- инструкцию сборки ".exe";
- список реализованных функций;
- список известных ограничений.