Загрузка данных
Ты работаешь в текущем проекте:
/home/work/skil-scrap/adt-markdownify-meta
Задача:
Реализовать только файл:
scripts/scrape_meta.py
Важно:
- Не трогай другие файлы.
- Не меняй config_loader.py.
- Не меняй markdown_writer.py.
- Не меняй html_to_markdown.py.
- Не меняй run_exporter.py.
- Мы НЕ используем API META.
- Мы НЕ используем requests/httpx/aiohttp/urllib.
- Мы работаем через браузерный скраппинг Playwright, как в hr-resume-scrapper.
Нужно реализовать:
1. Импорты:
from pathlib import Path
import time
from playwright.sync_api import sync_playwright
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
from scripts.html_to_markdown import build_meta_markdown
from scripts.markdown_writer import write_markdown, write_index, safe_filename
2. Функцию read_meta_urls(meta_urls_file: str) -> list
Логика:
- читает файл meta_urls.txt;
- если файла нет, выбрасывает FileNotFoundError с понятным текстом;
- пропускает пустые строки;
- пропускает строки, начинающиеся с "#";
- поддерживает формат:
СберНаЛадони - https://mapp.sberbank.ru/techcookbook-meta
- если строка содержит " - ", то всё до " - " считается name, всё после считается url;
- если строка начинается с http:// или https://, то name = "META page", url = строка;
- возвращает список словарей:
[
{
"name": "СберНаЛадони",
"url": "https://mapp.sberbank.ru/techcookbook-meta"
}
]
- если после чтения нет ни одной ссылки, выбрасывает ValueError.
3. Функцию save_html(temp_html_dir: str, title: str, html: str) -> Path
Логика:
- создаёт папку temp_html_dir, если её нет;
- делает безопасное имя файла через safe_filename(title);
- сохраняет HTML в файл с расширением .html;
- кодировка utf-8;
- возвращает Path к созданному файлу.
4. Функцию launch_browser(playwright, config: dict)
Логика:
- читает config["browser"]["type"];
- если type = "chromium", запускает playwright.chromium.launch;
- если type = "sberbrowser", запускает playwright.chromium.launch с executable_path из config["browser"]["path_to_exe"];
- headless берётся из config["browser_settings"]["headless"];
- slow_mo берётся из config["browser_settings"]["slow_mo"];
- если type = "sberbrowser", но path_to_exe пустой, выбрасывает ValueError с понятным текстом;
- если type неизвестный, выбрасывает ValueError.
5. Функцию export_meta(config: dict)
Логика:
- читает из config:
- meta_urls_file
- output_dir
- temp_html_dir
- browser_settings.viewport_width
- browser_settings.viewport_height
- browser_settings.wait_until
- browser_settings.page_load_timeout
- scraping.max_retries
- scraping.retry_delay
- scraping.request_delay
- читает список ссылок через read_meta_urls;
- запускает браузер через sync_playwright;
- создаёт browser context с viewport;
- для каждой ссылки:
- выводит в консоль прогресс;
- открывает новую страницу;
- делает page.goto(url, wait_until=wait_until, timeout=page_load_timeout);
- получает HTML через page.content();
- сохраняет HTML через save_html;
- конвертирует HTML в Markdown через build_meta_markdown;
- если build_meta_markdown вернул title, использует его;
- если title пустой, использует name из meta_urls.txt;
- сохраняет Markdown через write_markdown;
- добавляет результат в exported_files;
- закрывает страницу;
- делает паузу request_delay секунд;
- если страница не открылась, повторяет попытку max_retries раз;
- между попытками ждёт retry_delay секунд;
- если после всех попыток страница не выгрузилась, выводит ошибку и идёт к следующей ссылке;
- после всех ссылок создаёт output/README.md через write_index;
- закрывает браузер.
6. Требования к ошибкам:
- если META требует авторизацию, скрипт не должен сохранять логины, пароли, cookie или token;
- если headless = false, пользователь сможет войти вручную в открытом браузере;
- ошибки должны быть понятными;
- при ошибке одной ссылки скрипт не должен падать полностью, а должен перейти к следующей ссылке.
7. Требования к коду:
- Код должен быть простым и понятным.
- Не добавляй API.
- Не добавляй endpoint-ы.
- Не добавляй requests/httpx/aiohttp/urllib.
- Не добавляй токены, cookie, login, password.
- Все файлы сохраняй в utf-8.
После реализации покажи полный код файла scripts/scrape_meta.py.