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


Ты работаешь с двумя проектами:

Старый проект-образец:
/home/sigma.sbrf.ru@23865613/home/work/hr-resume-scrapper-master

Новый проект:
/home/sigma.sbrf.ru@23865613/home/work/skil-scrap/adt-markdownify-meta

Контекст нового проекта:
У нас уже есть режим cdp_existing. Он нужен для подключения к уже открытому SberBrowser через remote-debugging-port=9222.

Проблема:
Скрипт не должен каждый раз запускать новый SberBrowser и не должен закрывать уже открытый SberBrowser.

Пользователь сам запускает SberBrowser вручную командой:

/opt/Sberbrowser/sberbrowser/sberbrowser \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/sberbrowser-meta-profile \
  --no-sandbox \
  --disable-setuid-sandbox \
  --disable-dev-shm-usage

После этого пользователь сам открывает нужную вкладку META.

Скрипт должен только:
1. Подключиться к уже открытому SberBrowser.
2. Найти уже открытую вкладку META.
3. Выгрузить HTML.
4. Сохранить Markdown.
5. Отключиться от CDP.
6. Не закрывать SberBrowser.

Дополнительная проблема:
SberBrowser запускается с remote-debugging-port=9222, в терминале появляется:

DevTools listening on ws://127.0.0.1:9222/devtools/browser/...

Но дальше в логах SberBrowser много ошибок:
- failed to connect to MCS endpoint
- component updater errors
- password manager / login database errors
- QUOTA_EXCEEDED
- ERR_CERT_AUTHORITY_INVALID
- DIRECTED_ENDPOINT
- ошибки расширений

Также ранее обычный browser mode зависал и не создавал страницу.
Нужно понять, как похожий проект hr-resume-scrapper-master обходил такие проблемы при запуске SberBrowser, и после этого доработать новый проект.

ВАЖНО:
- Ничего не меняй в старом проекте.
- В новом проекте меняй только явно указанные файлы.
- Ничего не удаляй.
- Не запускай полный scraping.
- Не скачивай зависимости.
- Не добавляй API.
- Не добавляй endpoint-ы.
- Не добавляй requests/httpx/aiohttp/urllib.
- Не добавляй token, cookie, login, password.
- Не сохраняй cookies.
- Не сохраняй session storage/local storage.
- Не закрывай SberBrowser из скрипта.
- Не запускай python run_exporter.py автоматически.
- Все выводы по старому проекту подтверждай конкретными файлами, функциями и фрагментами кода.
- Если чего-то нет — прямо пиши "не найдено".

============================================================
ЧАСТЬ 1. АНАЛИЗ СТАРОГО ПРОЕКТА hr-resume-scrapper-master
============================================================

Перейди в старый проект:

cd /home/sigma.sbrf.ru@23865613/home/work/hr-resume-scrapper-master

1. Где запускается браузер

Найди:

grep -R "sync_playwright" -n .
grep -R "chromium.launch" -n .
grep -R "launch_persistent_context" -n .
grep -R "connect_over_cdp" -n .
grep -R "new_context" -n .
grep -R "new_page" -n .
grep -R "page.goto" -n .

Для каждого найденного места покажи:
- файл;
- функцию;
- фрагмент кода;
- что делает.

2. Какие browser args используются

Найди:

grep -R "no-sandbox" -n .
grep -R "disable-setuid-sandbox" -n .
grep -R "disable-dev-shm-usage" -n .
grep -R "disable-gpu" -n .
grep -R "ignore-certificate-errors" -n .
grep -R "allow-insecure-localhost" -n .
grep -R "disable-extensions" -n .
grep -R "disable-component-update" -n .
grep -R "disable-background-networking" -n .
grep -R "disable-sync" -n .
grep -R "password-store" -n .
grep -R "use-mock-keychain" -n .
grep -R "user-data-dir" -n .
grep -R "remote-debugging-port" -n .

Сделай таблицу:
- аргумент;
- найден или нет;
- где найден;
- зачем он может быть нужен.

3. Как старый проект работает с SberBrowser

Найди:

grep -R "sberbrowser" -n .
grep -R "SberBrowser" -n .
grep -R "path_to_exe" -n .
grep -R "executable_path" -n .

Выясни:
- где задаётся путь к SberBrowser;
- передаётся ли executable_path;
- используется ли системный путь Linux;
- есть ли отдельные настройки под SberBrowser.

4. Как старый проект ждёт загрузку страницы

Найди:

grep -R "wait_until" -n .
grep -R "domcontentloaded" -n .
grep -R "networkidle" -n .
grep -R "wait_for_selector" -n .
grep -R "wait_for_timeout" -n .
grep -R "sleep" -n .
grep -R "timeout" -n .

Выясни:
- какой wait_until используется;
- какие timeout;
- ждёт ли проект selector;
- есть ли ручные паузы;
- есть ли retry.

5. Как старый проект обрабатывает ошибки SberBrowser

Найди:

grep -R "TimeoutError" -n .
grep -R "Exception" -n .
grep -R "retry" -n .
grep -R "max_retries" -n .
grep -R "try:" -n scripts
grep -R "except" -n scripts

Выясни:
- падает ли проект при ошибке одной ссылки;
- продолжает ли со следующей;
- какие сообщения пишет;
- закрывает ли страницу;
- закрывает ли браузер.

6. Использует ли старый проект уже открытую вкладку

Проверь:
- есть ли connect_over_cdp;
- есть ли remote-debugging-port;
- есть ли подключение к уже открытому браузеру;
- есть ли поиск page.url;
- есть ли browser.contexts/page.pages.

Если нет — прямо напиши:

"В старом проекте не найден режим подключения к уже открытому браузеру".

7. Что из старого проекта можно перенести в новый

Сравни с новым файлом:

/home/sigma.sbrf.ru@23865613/home/work/skil-scrap/adt-markdownify-meta/scripts/scrape_meta.py

Нужно сказать:
- каких browser args не хватает в новом проекте;
- нужно ли добавить ignore-certificate-errors;
- нужно ли добавить disable-component-update;
- нужно ли добавить disable-background-networking;
- нужно ли добавить disable-sync;
- нужно ли добавить password-store=basic;
- нужно ли добавить use-mock-keychain;
- нужно ли добавить отдельный user-data-dir;
- нужно ли продолжать CDP existing mode, если старый проект такого не делал.

8. Очень важный вывод по старому проекту

Ответь конкретно:

- Старый проект реально обходил запуск уже открытого SberBrowser или нет?
- Старый проект просто запускал новый SberBrowser через Playwright или подключался к существующему?
- Есть ли в старом проекте решение для ошибок DevTools/MCS/component updater?
- Какие параметры запуска из старого проекта стоит перенести в новый?
- Какие ошибки можно игнорировать, если DevTools listening появился?
- Что нужно попробовать следующим шагом в новом проекте?

Формат отчёта по старому проекту:

# Отчёт: как hr-resume-scrapper обходил проблемы SberBrowser

## 1. Где запускается браузер

## 2. Какие browser args используются

## 3. Как подключается SberBrowser

## 4. Как открывается страница

## 5. Как старый проект ждёт загрузку

## 6. Как обрабатываются ошибки

## 7. Есть ли подключение к уже открытому браузеру

## 8. Что перенести в adt-markdownify-meta

## 9. Главный вывод

В конце дай короткий список:
"Что попробовать дальше" — максимум 5 пунктов.

============================================================
ЧАСТЬ 2. ДОРАБОТКА НОВОГО ПРОЕКТА adt-markdownify-meta
============================================================

Теперь перейди в новый проект:

cd /home/sigma.sbrf.ru@23865613/home/work/skil-scrap/adt-markdownify-meta

Задача:
Доработать режим cdp_existing так, чтобы он:

1. Не запускал SberBrowser.
2. Не закрывал SberBrowser.
3. Подключался к уже открытому SberBrowser через connect_over_cdp.
4. Искал уже открытую вкладку META.
5. Ждал появления вкладки максимум 60 секунд, а не 120 секунд.
6. После выгрузки отключался от CDP, но не закрывал браузер.
7. Если вкладка не найдена, завершался понятной ошибкой.
8. Если в браузере несколько вкладок с sberbank.ru, выводил список найденных вкладок.

Менять можно только:

1. meta_exporter.yaml.example
2. scripts/scrape_meta.py
3. README.md, если там есть инструкция по cdp_existing

Файл meta_exporter.yaml.example

В блок cdp добавь или обнови настройки:

cdp:
  endpoint_url: "http://127.0.0.1:9222"
  target_url_contains: "sberbank.ru"
  fallback_title: "META page"
  wait_timeout_seconds: 60
  poll_interval_seconds: 2

Важно:
target_url_contains лучше поставить "sberbank.ru", а не только "meta.sberbank.ru", потому что адрес может отличаться.

Файл scripts/scrape_meta.py

Нужно доработать функцию:

export_meta_from_existing_browser(config: dict)

Логика должна быть такая:

1. Прочитать настройки:

endpoint_url = config["cdp"]["endpoint_url"]
target_url_contains = config["cdp"]["target_url_contains"]
fallback_title = config["cdp"].get("fallback_title", "META page")
wait_timeout_seconds = config["cdp"].get("wait_timeout_seconds", 60)
poll_interval_seconds = config["cdp"].get("poll_interval_seconds", 2)

Также прочитать:

output_dir = config["output_dir"]
temp_html_dir = config["temp_html_dir"]

2. Подключиться к открытому браузеру:

with sync_playwright() as pw:
    browser = pw.chromium.connect_over_cdp(endpoint_url)

3. В режиме cdp_existing запрещено:

- НЕ создавать новую страницу через new_page()
- НЕ вызывать page.goto()
- НЕ вызывать browser.close()
- НЕ запускать SberBrowser
- НЕ сохранять cookie/session/local storage

4. Добавить вспомогательную функцию:

def find_existing_page(browser, target_url_contains: str):
    matched_pages = []

    for context in browser.contexts:
        for page in context.pages:
            page_url = page.url or ""
            if target_url_contains in page_url:
                matched_pages.append(page)

    if matched_pages:
        print("Найдены подходящие вкладки:")
        for idx, page in enumerate(matched_pages, start=1):
            print(f"{idx}. {page.url}")
        return matched_pages[0]

    return None

5. В export_meta_from_existing_browser искать вкладку так:

- сначала попробовать найти сразу;
- если не найдена:
  - ждать до wait_timeout_seconds;
  - каждые poll_interval_seconds повторно смотреть browser.contexts и context.pages;
  - выводить понятное сообщение:
    "Ожидаю открытую вкладку META до 60 секунд..."

Пример логики:

start_time = time.time()
target_page = None

while time.time() - start_time < wait_timeout_seconds:
    target_page = find_existing_page(browser, target_url_contains)
    if target_page:
        break
    print(f"Ожидаю открытую вкладку META до {wait_timeout_seconds} сек...")
    time.sleep(poll_interval_seconds)

6. Если вкладка не найдена за 60 секунд:

- вызвать browser.disconnect(), если метод доступен;
- НЕ вызывать browser.close();
- вывести понятную ошибку:

"Не найдена открытая вкладка META. Откройте META в SberBrowser, который запущен с --remote-debugging-port=9222"

- завершить без закрытия SberBrowser.

Можно сделать через raise RuntimeError с понятным текстом.

7. Если вкладка найдена:

- вывести URL найденной вкладки;
- получить url = target_page.url;
- получить title:

try:
    title = target_page.title().strip()
except Exception:
    title = ""

if not title:
    title = fallback_title

- получить html = target_page.content()
- сохранить HTML через save_html(temp_html_dir, title, html)
- конвертировать HTML через build_meta_markdown(html, url)
- сохранить Markdown через write_markdown(output_dir, title, url, markdown)
- создать README.md через write_index(output_dir, exported_files)
- вывести путь к созданному Markdown

8. После завершения:

- НЕ вызывать browser.close()
- вызвать browser.disconnect(), если такой метод есть
- если disconnect недоступен, просто выйти из функции
- SberBrowser должен остаться открытым

Пример безопасного отключения:

try:
    browser.disconnect()
except Exception:
    pass

README.md

Обновить инструкцию для cdp_existing:

## Режим cdp_existing: выгрузка уже открытой вкладки META

1. Сначала вручную запустить SberBrowser с портом 9222:

/opt/Sberbrowser/sberbrowser/sberbrowser \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/sberbrowser-meta-profile \
  --no-sandbox \
  --disable-setuid-sandbox \
  --disable-dev-shm-usage

2. Не закрывать терминал, где запущен SberBrowser.
3. В этом SberBrowser открыть нужную страницу META.
4. Выбрать сертификат и выполнить вход.
5. Убедиться, что вкладка с META открыта.
6. В другом терминале запустить:

cd /home/sigma.sbrf.ru@23865613/home/work/skil-scrap/adt-markdownify-meta
source .venv/bin/activate
export PLAYWRIGHT_NODEJS_PATH=/usr/bin/node
python run_exporter.py

7. Скрипт не закрывает SberBrowser.
8. Скрипт ждёт вкладку 60 секунд.
9. Если вкладка не найдена, проверить:
   - SberBrowser запущен именно с --remote-debugging-port=9222;
   - META открыта именно в этом окне SberBrowser;
   - cdp.target_url_contains совпадает с частью URL;
   - при необходимости поставить target_url_contains: "sberbank.ru".

Проверка после правок:

Выполни только проверку синтаксиса:

python -m py_compile run_exporter.py scripts/config_loader.py scripts/scrape_meta.py scripts/html_to_markdown.py scripts/markdown_writer.py

Не запускай python run_exporter.py автоматически.

В конце покажи:

1. Отчёт по старому проекту.
2. Обновлённый блок cdp из meta_exporter.yaml.example.
3. Полный код функции export_meta_from_existing_browser.
4. Полный код вспомогательной функции find_existing_page, если добавил.
5. Кратко напиши, что SberBrowser теперь не закрывается и ожидание вкладки равно 60 секунд.