import os import subprocess import time import re from pathlib import Path from playwright.sync_api import sync_playwright # --- CONFIG --- STORAGE_ROOT = Path("/app/services/gis_harvester/contracts") NAS_PATH = "/volume1/web/legal/gis/contracts" BOT_TOKEN = "8725618164:AAH1tGalq-pw1l0t4P5c0sdLkCVJdh7IE7M" CHAT_ID = "197957361" def send_tg_status(msg): subprocess.run(["curl", "-s", "-X", "POST", f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage", "-d", f"chat_id={CHAT_ID}&text={msg}&parse_mode=markdown"]) def sync_to_nas(local_path, remote_folder): target = f"{NAS_PATH}/{remote_folder}" subprocess.run(["ssh", "matrixhasyou@192.168.10.105", f"mkdir -p {target}"]) for f in os.listdir(local_path): src = local_path / f dst = f"{target}/{f}" with open(src, "rb") as fd: subprocess.run(["ssh", "matrixhasyou@192.168.10.105", f"cat > '{dst}'"], stdin=fd) def run_harvest(): with sync_playwright() as p: try: browser = p.chromium.connect_over_cdp("http://127.0.0.1:9222") page = browser.contexts[0].pages[0] # Мы уже на нужной странице (#!/agreements/citizen/...) print("[*] Сбор списка договоров...") page.wait_for_load_state("networkidle") time.sleep(10) # Находим все ссылки на просмотр договоров # Обычно это ссылки вида #!/agreements/view/... links = page.locator("a[href*='agreements/view/']").all() total = len(links) send_tg_status(f"📜 **ЖНЕТЦ ДОГОВОРОВ**\nНайдено в разделе: {total} договоров.") for i in range(total): # Находим ссылки заново т.к. DOM может обновиться current_links = page.locator("a[href*='agreements/view/']").all() link = current_links[i] # Получаем название договора из родительской строки row = page.locator(f"tr:has(a[href*='{link.get_attribute('href')}'])") name_text = row.inner_text().split('\n')[0][:100].replace('/', '_').replace(' ', '_') print(f"[{i+1}/{total}] Вход в договор: {name_text}...") link.click() page.wait_for_load_state("networkidle") time.sleep(15) # СКРИНШОТ case_dir = STORAGE_ROOT / name_text case_dir.mkdir(parents=True, exist_ok=True) page.screenshot(path=str(case_dir / "contract_evidence.png"), full_page=True) # СКАЧИВАНИЕ try: # В договорах кнопка может называться по-другому, но часто это тоже 'Скачать все' download_btn = page.get_by_text("Скачать все").first if download_btn.is_visible(): with page.expect_download(timeout=120000) as download_info: download_btn.click() download = download_info.value zip_path = case_dir / "contract_files.zip" download.save_as(str(zip_path)) # Синхронизация sync_to_nas(case_dir, name_text) status = "✅ ZIP + Скрин" else: sync_to_nas(case_dir, name_text) status = "⚠️ Только скрин (кнопка скачивания не найдена)" except Exception as e: status = f"❌ Ошибка: {str(e)}" send_tg_status(f"📜 **ДОГОВОР: {name_text}**\nСтатус: {status}\n[{i+1}/{total}]") # Назад в список page.go_back() time.sleep(10) send_tg_status("🏁 Жатва договоров ЗАВЕРШЕНА.") browser.close() except Exception as e: send_tg_status(f"🚨 СБОЙ ЖНЕЦА ДОГОВОРОВ: {str(e)}") if __name__ == "__main__": os.makedirs(STORAGE_ROOT, exist_ok=True) run_harvest()