#!/usr/bin/env python3 """Подготовка русскоязычной заливки корпуса — сидинг parse_sources (CyberLeninka). Зачем: корпус на ~99% английский (0 русских источников), хотя сервис — для русских студентов. Этот скрипт создаёт в таблице `parse_sources` набор заданий CyberLeninka по основным студенческим дисциплинам. Он НЕ запускает заливку — только готовит задания; их затем триггерят (кнопка «Запустить» в админке или Celery-задача `index.run_parser(source_id)`). Идемпотентно: источник с таким `name` повторно не создаётся. Запуск: # dry-run — показать план, ничего не писать: python scripts/seed_ru_sources.py # создать источники в БД (лимит на каждую дисциплину): python scripts/seed_ru_sources.py --apply --limit 500 Креды PG берутся из .env (POSTGRES_HOST/PORT/DB/USER/PASSWORD) или окружения. ВНИМАНИЕ: локальный .env может указывать на старый PG — для прода используйте POSTGRES_HOST=192.168.1.38 (см. вывод по наполненности базы). """ import argparse import os import sys from pathlib import Path # Студенческие дисциплины → поисковый запрос в CyberLeninka (русскоязычный). DISCIPLINES = [ "экономический анализ", "менеджмент организации", "бухгалтерский учёт", "финансы и кредит", "маркетинг", "гражданское право", "уголовное право", "конституционное право", "трудовое право", "педагогика", "психология личности", "социология", "философия науки", "история России", "политология", "информационные технологии", "программирование", "базы данных", "математический анализ", "физика", "химия", "биология", "медицина", "экология", "лингвистика", "литературоведение", "государственное управление", "международные отношения", "журналистика", "культурология", ] def _load_env() -> None: """Подтянуть переменные из .env репозитория, если файл есть.""" env = Path(__file__).resolve().parent.parent / ".env" if not env.exists(): return for line in env.read_text(encoding="utf-8").splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue key, _, val = line.partition("=") os.environ.setdefault(key.strip(), val.strip()) def _pg_dsn() -> dict: return { "host": os.environ.get("POSTGRES_HOST", "localhost"), "port": int(os.environ.get("POSTGRES_PORT", "5432")), "dbname": os.environ.get("POSTGRES_DB", "antiplagiator"), "user": os.environ.get("POSTGRES_USER", "antiplagiator"), "password": os.environ.get("POSTGRES_PASSWORD", ""), } def main() -> None: ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--apply", action="store_true", help="реально записать в БД (иначе dry-run)") ap.add_argument("--limit", type=int, default=500, help="лимит документов на дисциплину") ap.add_argument("--source-type", default="cyberleninka", help="тип парсера (по умолчанию cyberleninka)") args = ap.parse_args() _load_env() rows = [(f"ru:{d}", args.source_type, d) for d in DISCIPLINES] print(f"Дисциплин: {len(rows)} | тип: {args.source_type} | лимит/шт: {args.limit}") print(f"Потенциальный объём: ~{len(rows) * args.limit} документов") if not args.apply: print("\n[dry-run] будут созданы источники (name → query):") for name, _, q in rows: print(f" {name:38} → {q!r}") print("\nЗапустите с --apply, чтобы записать в parse_sources.") return try: import psycopg2 except ImportError: sys.exit("Нужен psycopg2 (есть в образах воркеров). Запускайте на app-хосте/в контейнере.") dsn = _pg_dsn() print(f"\nПодключение к PG {dsn['host']}:{dsn['port']}/{dsn['dbname']} ...") conn = psycopg2.connect(**dsn) conn.autocommit = True created, skipped, ids = 0, 0, [] with conn.cursor() as cur: for name, stype, query in rows: cur.execute("SELECT id FROM parse_sources WHERE name = %s", (name,)) existing = cur.fetchone() if existing: skipped += 1 continue cur.execute( 'INSERT INTO parse_sources ' '(source_type, name, query, lang, "limit", enabled, last_status, docs_added) ' "VALUES (%s, %s, %s, 'ru', %s, TRUE, 'idle', 0) RETURNING id", (stype, name, query, args.limit), ) ids.append(cur.fetchone()[0]) created += 1 conn.close() print(f"Создано: {created}, пропущено (уже были): {skipped}") if ids: print(f"ID новых источников: {ids}") print("\nЗапуск заливки (после проверки источников):") print(" • Админка → раздел «Источники» → «Запустить» у каждого, ЛИБО") print(" • Celery: for i in ids: index.run_parser.delay(i)") print("Рекомендация: сначала запустить 1-2 для проверки темпа/качества, потом остальные.") if __name__ == "__main__": main()