Загрузка данных



Вот обновленный промт. Я интегрировал все технические правки (защита Excel, сброс контекста, асинхронность, современные методы pandas, пошаговая генерация), полностью сохранив твой изначальный контекст, бизнес-логику и структуру.
Теперь его можно смело копировать и отправлять в нейросеть.
РОЛЬ И КОНТЕКСТ
Ты — Senior Python Backend Developer, QA-инженер и специалист по браузерной автоматизации (Playwright).
Твоя задача — написать production-ready код для проекта  nmonitor  (полуавтоматическая система мониторинга агентств недвижимости Иркутска на площадках Авито, ЦИАН, Домклик).
Стек: Python 3.11+, asyncio, Playwright (Chromium, строго асинхронный синтаксис  async/await ), pandas (использовать только современные методы, без устаревшего  df.append , только  pd.concat ), openpyxl.
Хранилище: Локальные Excel-файлы (Master-файл  companies.xlsx  + отчеты в  reports/ ). БД не используем.
Прокси: Не используем.
Режим браузера:  headless=False  (видимый браузер).
Запуск: С личного ПК пользователя, по кнопке через консольное меню.
БИЗНЕС-ЛОГИКА И АРХИТЕКТУРА
Скрипт 1: Сборщик профилей ( script1_search.py )
Запускается отдельно для каждой площадки через меню.
1.
Авито: Каталог агентств отсутствует. Поиск осуществляется путем листания объявлений вторички по Иркутску. Листать до конца, пока активна кнопка «Следующая страница». Важно: После клика на кнопку обязательно жди изменения URL (добавление  ?p=X ) или появления новых блоков объявлений (через  wait_for_selector  или  wait_for_load_state ), чтобы гарантированно не начать парсить старую страницу.
2.
ЦИАН и Домклик: Парсинг через официальные каталоги агентств.
3.
Обновление базы: При повторном запуске скрипт читает  companies.xlsx . Если найденное агентство уже есть в базе (совпадение по очищенному названию), скрипт дописывает ссылку на эту площадку в существующую строку. Если компании нет — создает новую строку.
Скрипт 2: Счетчик и анализ ( script2_counter.py )
Запускается для всех площадок сразу.
1.
Читает ссылки из  companies.xlsx .
2.
Переходит по каждой ссылке, парсит текущее количество объявлений.
3.
Сравнивает результаты с последним по дате отчетом в папке  reports/  (определять не по имени файла, а по максимальному времени модификации  os.path.getmtime ).
4.
Сохраняет новый отчет  report_hh-mm_DD-MM-YYYY.xlsx .
Структура Master-файла ( companies.xlsx )
Логика статусов (колонка «Примечание»)
Профиль новый: Компания отсутствует в предыдущем отчете.
Профиль создан: В прошлом отчете было  0 , сейчас >  0 .
Профиль удалён: В прошлом отчете было >  0 , сейчас  0 .
не получено: Капча, блокировка, ошибка сети или изменение верстки.
ЖЕСТКИЕ ПРАВИЛА И АЛГОРИТМЫ
1.
Идентификация и матчинг:
Только по названию. Очистка строки: удаление кавычек, организационно-правовых форм (ООО, АО, ИП), приведение к нижнему регистру, удаление лишних пробелов.
Нечеткий поиск (fuzzy matching) не использовать. Строгое совпадение очищенных строк. Одноименные компании считаются разными, если строки не совпадают идеально после очистки.
2.
Обработка ошибок и «не получено»:
Статус  не получено  игнорируется при расчете дельты (сравнении с прошлым отчетом). Он не должен триггерить статус «Профиль удалён».
Если парсинг одной компании упал с ошибкой, скрипт пишет  не получено , логирует ошибку в консоль и переходит к следующей компании. Цикл не прерывать.
3.
Обход капчи:
Автоматическое решение капчи не реализуется.
При обнаружении селектора капчи на странице скрипт выводит в консоль сообщение:  Обнаружена капча. Решите её в браузере вручную и нажмите Enter...  и вызывает  input() . После нажатия Enter скрипт продолжает работу с текущей страницы.
4.
Защита от банов и утечек памяти:
User-Agent: реалистичный Chrome.
Случайные паузы между запросами: 8–15 секунд.
Случайные паузы между страницами: 10–20 секунд.
Эмуляция скроллинга страницы перед чтением DOM-дерева.
Сброс контекста: В  script2_counter.py  каждые 15-20 обработанных компаний полностью закрывай  browser_context  и создавай новый, чтобы избежать утечек памяти и накопления кэша/куки.
5.
Отказоустойчивость и безопасная запись:
Скрипт 1: Сохраняет  companies.xlsx  после обработки каждой страницы пагинации.
Скрипт 2: Сохраняет черновик отчета каждые 10 обработанных компаний.
Безопасная запись Excel: При любом промежуточном и финальном сохранении  companies.xlsx  и отчетов, сначала пиши данные во временный файл (например,  temp_companies.xlsx ), а затем заменяй им оригинал через  os.replace() . Это спасет базу от превращения в мусор (0 байт) при внезапном краше скрипта.
6.
CSS-селекторы:
Пиши максимально устойчивые селекторы (опирайся на  data-*  атрибуты,  aria-label , уникальные классы).
Все селекторы выноси в  config.py .
Возле каждого селектора оставляй комментарий  # TODO: CHECK SELECTOR (F12) , так как верстка может измениться.
ТЕКУЩАЯ ЗАДАЧА
Напиши полный, рабочий код всех файлов проекта без сокращений и заглушек ( pass  или  ... ).
Файлы для генерации:
1.
 config.py  (URL, паузы, словарь селекторов для 3 площадок)
2.
 utils.py  (функции очистки названий, работы с Excel, генерации пауз)
3.
 script1_search.py  (классы/функции парсинга для Авито, ЦИАН, Домклик с логикой обновления строк)
4.
 script2_counter.py  (логика обхода профилей, сравнения с прошлым отчетом и простановки меток)
5.
 main.py  (консольное меню)
6.
 requirements.txt 
Формат ответа и ПОШАГОВАЯ ГЕНЕРАЦИЯ:
Из-за ограничения на длину ответа, не пиши весь код сразу. Работай строго по шагам:
Шаг 1: Напиши  config.py ,  utils.py ,  requirements.txt  и  main.py . Код блоками с указанием имени файла, краткие пояснения архитектуры после кода. В конце ответа задай один вопрос по граничному кейсу, если он остался.
Шаг 2: Остановись и дождись моей команды "Дальше", чтобы написать  script1_search.py .
Шаг 3: Остановись и дождись моей команды для  script2_counter.py .